static keyword in non-class functions?

  • Thread starter Thread starter Egbert Nierop \(MVP for IIS\)
  • Start date Start date
E

Egbert Nierop \(MVP for IIS\)

Hi,

Why do I need to define a function as static (inside a .h file) to avoid the
following linker error?

CSession error LNK2005: "void __stdcall AllocString(unsigned short *
*,unsigned int)" (?AllocString@@YGXPAPAGI@Z) already defined in stdafx.obj

I know that the MSDN talks about this, but not why it is needed.
ms-help://MS.MSDNQTR.2005APR.1033/vccore/html/LNK2005.htm

and b.t.w. the file is included only once and it has #pragma once

Thanks...
 
Egbert said:
Hi,

Why do I need to define a function as static (inside a .h file) to avoid
the following linker error?

CSession error LNK2005: "void __stdcall AllocString(unsigned short *
*,unsigned int)" (?AllocString@@YGXPAPAGI@Z) already defined in stdafx.obj

I know that the MSDN talks about this, but not why it is needed.
ms-help://MS.MSDNQTR.2005APR.1033/vccore/html/LNK2005.htm

and b.t.w. the file is included only once and it has #pragma once

Thanks...

C and C++ have a rule known as the "one definition rule". Under this
rule, each function may only have one definition in a particular
program. If you have two different source files that include the header
you mention, then your program will actually have two definitions of
AllocString available to it, one in each of the source files, which
causes the linker to complain (when linking, it tries to resolve all
references to a function to the definition of that function, but you
have two definitions, so it doesn't know which one to pick).

Static "fixes" the problem since then the definition of AllocString is
private to the two source files that use it, but you end up with two
independent copies of AllocString, one in each source file - in effect,
you now have two different AllocString functions that happen to share
the same name.

Other fixes include:
- Move the _definition_ of AllocString out of the header and into a
source file. Obviously the declaration should stay in the header.
- Put "inline" in front of the function declaration.

Note that #pragma once/include guards/etc. don't help here, since that
only ensures that a header is only included once for a particular source
file, not across the whole program.

Tom
 
Tom Widmer said:
Egbert Nierop (MVP for IIS) wrote:
Note that #pragma once/include guards/etc. don't help here, since that
only ensures that a header is only included once for a particular source
file, not across the whole program.

Though I'm not sure about the pragma, why wouldn't include guards
work? They're based on compiler directives. If the define is true,
it should jump to the #endif. If this weren't true, how could templates
work when their definitions are all in the header file? Does the
compiler treat non class templates differently somehow?
 
Tom Widmer said:
C and C++ have a rule known as the "one definition rule". Under this rule,
each function may only have one definition in a particular program. If you
have two different source files that include the header you mention, then
your program will actually have two definitions of AllocString available
to it, one in each of the source files, which causes the linker to
complain (when linking, it tries to resolve all references to a function
to the definition of that function, but you have two definitions, so it
doesn't know which one to pick).

Static "fixes" the problem since then the definition of AllocString is
private to the two source files that use it, but you end up with two
independent copies of AllocString, one in each source file - in effect,
you now have two different AllocString functions that happen to share the
same name.

Other fixes include:
- Move the _definition_ of AllocString out of the header and into a source
file. Obviously the declaration should stay in the header.
- Put "inline" in front of the function declaration.



Thanks...

This solved my 'problem' :)

I did not know, the compiler worked like this. So I only include the .h file
while the .cpp 'seems' unreferenced in the project.
 
Duane said:
Though I'm not sure about the pragma, why wouldn't include guards
work? They're based on compiler directives. If the define is true,
it should jump to the #endif. If this weren't true, how could templates
work when their definitions are all in the header file? Does the
compiler treat non class templates differently somehow?

This is the linker error. In the following example the linker will
notice that problematic function is defined twice.

First.cpp
 
Duane said:
Though I'm not sure about the pragma, why wouldn't include guards
work? They're based on compiler directives. If the define is true,
it should jump to the #endif. If this weren't true, how could
templates
work when their definitions are all in the header file? Does the
compiler treat non class templates differently somehow?

Yes - Templates are special in that the compiler is required to merge
multiple definitions of a template function or template class, as long as
they're all the same (otherwise it's an ODR - One Definition Rule -
violation). While templates need not be all inline (though they frequently
are), they get essentially the same treatment from the compiler as an inline
function that wasn't in fact inlined (since the compiler is free to ignore
any inline suggestion that you give, and routinely does so in debub builds).

-cd
 
Yes - Templates are special in that the compiler is required to merge
multiple definitions of a template function or template class, as long as
they're all the same (otherwise it's an ODR - One Definition Rule -
violation). While templates need not be all inline (though they frequently
are), they get essentially the same treatment from the compiler as an inline
function that wasn't in fact inlined (since the compiler is free to ignore
any inline suggestion that you give, and routinely does so in debub builds).

Thanks. But I'm still not seeing why header guards don't work. Once
a header guard is passed, shouldn't the code in the header be read
once and the next time it's seen shouldn't the #ifndef/#endif take it
out of the picture? Is this something that happens only for free
functions? If you put them in a namespace does this solve the
problem?

Like I said before, I don't remember ever having free functions
defined in a header file (except for templates) I'm just curious
why this would be a problem. Thanks for the explanation.
 
Duane said:
Thanks. But I'm still not seeing why header guards don't work. Once
a header guard is passed, shouldn't the code in the header be read
once

Once per unit, not once per project. If you define a function in a
header file H.h:

#pragma once
int MyFunc() { return 0; }

you can still include it from two different units:

//A.cpp
#include "H.h"

//B.cpp
#include "H.h"

which results in duplicate definition within the same project. A.obj
will contain MyFunc, and B.obj will contain it too, thus the linker will
complain about double definition. It's a linker error, not a compiler error.

Rule of thumb: Every non-member function implemented in the header file
must be explicitly declared inline, or the implementation must be moved
to the .cpp file, otherwise you run the risk of double definition.

Tom
 
Tamas said:
Rule of thumb: Every non-member function implemented in the header file
must be explicitly declared inline, or the implementation must be moved
to the .cpp file, otherwise you run the risk of double definition.

Correction: Every non-member non-template function [...]

Tom
 
Tamas Demjen said:
which results in duplicate definition within the same project. A.obj
will contain MyFunc, and B.obj will contain it too, thus the linker will
complain about double definition. It's a linker error, not a compiler error.

Rule of thumb: Every non-member function implemented in the header file
must be explicitly declared inline, or the implementation must be moved
to the .cpp file, otherwise you run the risk of double definition.

Thanks. I never realized that. I normally put the definitions in cpp files
anyway. BTW, what's this #pragma once? I imagine that it functions
like header guards but is it portable?
 
Back
Top