Link to home
Start Free TrialLog in
Avatar of lsmgms
lsmgms

asked on

Extern "C" confusion.

Hi,
I am confused with MSVC project file.  I have these files added to my project:
///////
Func1.CXX:
  void Func1(void)
  {
    return;
  }

/////////
Func1.H
  extern "C" void Func1(void);

//////////
Main.CXX

void main(void)
{
  Func1();
}

The above file can be compile but with this warning:

C:\projects\test\Main.cxx(10) : warning C4013: 'Func1' undefined; assuming extern returning int


If I try to include Func1.H:
#include "Func1.h"
void main(void)
{
  Func1();
}

C:\projects\test\Func.h(4) : error C2059: syntax error : 'string'


The only way that I can compile without error and warning is like thisL

extern void Func1(void); // Without "C"
void main(void)
{
  Func1();
}


But I don't understand because in Func1.h, i declare this with
  extern "C" void Func1(void);
but in Main.CXX it is declared as
  extern void Func1(void);


If C++ linkage convention is used,then I should be able to remove the extern "C" from Func1.h but the linker complains the error:

vmain.obj : error LNK2001: unresolved external symbol _Func1.

Can anybody help me.  Thanks.
Avatar of djbusychild
djbusychild

If I understand the situation correctly, then you're contradicting yourself, that's why the compiler is confused.

you're naming your func file with .cpp meaning that it's a c++ file, yet you're surround its prototype with extern "C"
so it can't find it.

rename func.cpp to func.c
Avatar of ambience
I think you also need to specify the linkage when you are defining the fuction , which i dont see in Func1.cXX

///////
Func1.CXX:

extern "C"  void Func1(void) << this should've been there
 {
   return;
 }

"djbusychild" is right.  extern "C" declares that the function is external as well as a C function.  In your main, the compiler looks for a name-mangled version of Func1 and can't find it.  Therefore you must compile Func1 as a C function... and the only way that I know is to name the file .c .  The other way is not to make Func1 a C function by declaring extern void Func1(void);

This is the answer!
//Func1.H
 extern "C" void Func1(void);


Ok so far, now:

//////////
// Main.CXX
void main(void)
{
 Func1();
}

Might be wise to declare Func1. Without declaration the compiler assumes that there is a int Func1() somewhere...

So:
//////////
// Main.CXX
#include "Func1.H"
void main(void)
{
 Func1();
}

Now we still need to define Func1, originally:
///////
//Func1.CXX:
 void Func1(void)
 {
   return;
 }

This defines Func1, the C++ compiler will use name-mangling appropriate for C++. Unfortunately the declaration stated it as extern "C", stating that C name-mangling is to be used.
To solve this, the definition must also be extern "C" 'd

///////
//Func1.CXX:
extern "C" void Func1(void)
 {
   return;
 }

or, if you have more functions extern "C"'d together:

///////
//Func1.CXX:
ectern "C" {
 void Func1(void)
 {
   return;
 }
}


>> This is the answer!

This is wrong.
1. The error happens, because in the file main.cxx the file "func1.h" is not included.
2. "extern C {}" declares that the part enclosed by the curly braces does not use mangled names. If a function is declared as "extern C" - provided that the compiler 'knows' this by including the definition in the file - it is compiled w/o name decoration, independently of the extension of the source file.

Cheers
snoegler
What a mess.  Lots of correct stuff, lots of incorrect stuff.

first a lesson in name decoration.

C++ use a name decoration as a means to differentiate between overloaded functions.  For example if you declare the two overloads.

F(int i)
F(double d);

does not create two functiosn called F().  If the functiosn were both called F the compiler and associated tools woudl be unable to differentiate between them and it would be very confussing.   Instead, for the internal workings off the compilation,  linking, and debugging purposes, the compiler creates two functions with decorated names.  These names are unique so that the tools can differeniate them.  For example, it might name these two functions F@int() and F@double().  (The naming scheme used depends on which compiler you use, but the details aren't important since you virtually never have to deal with these ames yourself.)

However, there is a problem with this.  C++ is (probably) the only language that does this.  At least there are many languages that don't.   So if you need to link your code with code from other langauges, you need to dissable this mechanism.  If you are calling functions from another language, you need to tell the compiler that the function does not have a decorated name.  If you want your fucntion to be called by another langauge, you want to tell the compiler to generate a function without a decorated name.  (So the code from the other langauge is looking for the right function name.)

This is what extern 'C' does.  It tells the compile that a partical function name should not be decorated.  If the compiler funds a definition for that function, then it generates that function's code and does not decorate the name of the function in the object file produced.    If the compiler does not find the function, it generates a request for the linker to link in the function, but using the non-decorated name.

Now when you use extern "C" on a function, it prevents the decoration used for making overloading work.  The effect of this is that you cannot have two overloads that both use extern "C".  Although you can still have overloads.  For example,  the following is okay.

int F(int i);
extern 'C' double F(double d);

but

extern "C" int F(int i);
extern 'C' double F(double d);

will not compile.

Now the first of these is partly what you've done.  You have generated two overloads for thsi function.  The file Func1.CXX: does not declare the function as extern "C" so it gnerates the function under a decorated name.  But the file Main.CXX sees an declaration for the function with an exntern 'C' so requests that the linker looks for the function without the decorated name.   But the function was given a decorated name, so it can't be found without the decoration.....

the easieast fix is that Func1.CXX should include Func1.h.  This way it will include the extern 'C' and the problem should go away.


Much of this has been said by the other experts before, I'm not trying to step on any toes, but I want to make it clear.
Avatar of lsmgms

ASKER

nietod,
>>What a mess.  Lots of correct stuff, lots of incorrect stuff.
Can you clrify which are the wrong stuffs?

I have changed the codes as follows:
///////
Func1.CXX:
 #include "Func1.h"
 extern "C" void Func1(void)
 {
   return;
 }

/////////
Func1.H
 extern "C" void Func1(void);

//////////
Main.CXX

void main(void)
{
 Func1();
}

Is this the correct one?
Do I need to #include "Func1.h" in the Main.CXX also?

Thanks for your help.
if you change Func1.cpp to Func1.c then you're basically telling the compiler that the whole file is enclosed in a big extern "C" {}.

so here are some of the the options

rename func1.cpp to func1.c and no need to include "func1.h" although it's GOOD PRATICE to always have a prototype

leave func1.cpp as it is, but include func1.h to it

leave func1.cpp as it is, don't include func1.h, but enclose it in extern "C"

did I cover all options?

ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
oh! and you should really do

#ifdef __cplusplus
#endif

around the extern "C" {

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif
>> if you change Func1.cpp to Func1.c then you're basically telling the
>> compiler that the whole file is enclosed in a big extern "C" {}
 But is there any reason to think that it is a desirable thing?  After all, this is the C++ topic area so it is likely that Ismgms wnats to program in C++, not C, and only has a limited number of functions that must have C linkage.
nietod, that's just one of the options. =)

I personally would suggest that you include the header (func1.h) in main.cpp and func1.cpp. Then, if you want to make your code clearer (although, redundant as nietod pointed out), you may enclose the declaration of func1 itself in extern "C".
Avatar of lsmgms

ASKER

Thanks for all the comments. I have solved the problem.  But now I have the problem of calling C function in C++.

// FuncX.CPP
extern "C" void FuncY(void);

void FuncX(void)
{
  FuncY()
}

// FuncY.C
extern "C" void FuncY(void)
{
}

I will counter the error:
error LNK2001: unresolved external symbol _FuncY

I though I have placed extern "C" at both of defination and declaration of FuncY, so that no decoration on the name of FuncY and the linker should be able to see it.  Is there any mistake I made?

I'm sorry that I am merging an existing C codes to another C++ project, and I am not allowed to do too many changes on the C code.  I will increase the points to appreaciate your help.

Avatar of lsmgms

ASKER

Sorry, I had found the problem, just some directive that mask the FuncY() defination.
I also should place extern "C" to FuncY because it is the C file.

Thanks everybody, thanks nietod.