Solved

Extern "C" confusion.

Posted on 2001-06-24
14
1,024 Views
Last Modified: 2012-06-27
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.
0
Comment
Question by:lsmgms
  • 4
  • 3
  • 3
  • +4
14 Comments
 
LVL 5

Expert Comment

by:djbusychild
Comment Utility
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
0
 
LVL 22

Expert Comment

by:ambience
Comment Utility
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;
 }

0
 

Expert Comment

by:pigsmayfly
Comment Utility
"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!
0
 
LVL 7

Expert Comment

by:KangaRoo
Comment Utility
//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;
 }
}


0
 
LVL 6

Expert Comment

by:snoegler
Comment Utility
>> 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
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
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.
0
 
LVL 1

Author Comment

by:lsmgms
Comment Utility
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.
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 5

Expert Comment

by:djbusychild
Comment Utility
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?

0
 
LVL 22

Accepted Solution

by:
nietod earned 100 total points
Comment Utility
>>Can you clrify which are the wrong stuffs?

>> 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.
However it is true its true that VC defaults to treating .cpp files as C++ ones and .c files as C one.  (But you can override this.  But the suggestion that "extern "c"" should not be used in a C++ files is wrong.  The "extern "C"" keywrods are C++, not C, In fact, if you try to use it in C it won't compile.

>> I think you also need to specify the linkage when you are defining the fuction ,
the linkage specifiers don't have to appear on the declaration.

>> extern "C" declares that the function is external as well as a C function.
"declares the function as external" is true, but missleading in the sense that the official meaning of "external" is very different than what people assume.  Basically it means that the function should be "exported" from any tranlsation unit that defines the function--which makes sense, but it should also be imported into any translation unit that uses it but does not define it--which is not really clear fro the name.    

It does not define the function as "C function"--whatever that would mean.  It means that the function does not have name decoration, which is true of C functions, but also true of Pascal functions etc etc etc.  It is certainly possible to write exnter "C" functions that cannot be C compatible, like ones that take classes as parameters, so clearly these are not C functions.

>> Might be wise to declare Func1. Without declaration the compiler assumes
>> that there is a int Func1() somewhere...
I'm not sure what kangaroo means.  There might be a typo here.  Kanagroo doesn't make mistakes often, but its not making sense to me--which always makes me a little nervious.

>> To solve this, the definition must also be extern "C" 'd
I'm fairly certain that is not right.  From the C++ draft standard section 7.5.5

 A
  function can be declared without  a  linkage  specification  after  an
  explicit  linkage  specification has been seen; the linkage explicitly
  specified in the earlier declaration is not affected by such  a  func-
  tion declaration.

>> 1. The error happens, because in the file main.cxx the file "func1.h" is not included.
True, but a little missleading.  The problem is that the function is not decalred as extern "C" in main's translation unit.  That is the problem.  Including func1.h would fix the problem since it does declare the function as extern "C", but that is not the only way to fix the problem, thus saying that is the error is really missleading.   However the suggestion is probably the easiest way and probably the best way to fix the problem.

>> #include "Func1.h"
>> extern "C" void Func1(void)
This extern "C" is redundant, but harmless.  its inclussion is a matter of taste--although I would do so.

>> Do I need to #include "Func1.h" in the Main.CXX also?
the main.cpp translation unit needs to see at least a declaration for Func1().  so someho you have to provide this declaration or it will fail to compile.  The best way to do so is probably to include Func1.h, since it has the declaration in it.
0
 
LVL 5

Expert Comment

by:djbusychild
Comment Utility
oh! and you should really do

#ifdef __cplusplus
#endif

around the extern "C" {

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> 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.
0
 
LVL 5

Expert Comment

by:djbusychild
Comment Utility
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".
0
 
LVL 1

Author Comment

by:lsmgms
Comment Utility
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.

0
 
LVL 1

Author Comment

by:lsmgms
Comment Utility
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.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now