Extern c ошибка

file1.c

int add(int a, int b)
{
  return (a+b);
}

file2.cpp

void main()
{
    int c;

    c = add(1,2);
}

h1.h

extern "C"  {

#include "stdio.h"

int add(int a,int b);
}

Case 1:
when i include h1.h in file1.c file then gcc compiler throw an error «expected ‘(‘ before string constant«.

case 2:
when I include h1.h in file2.cpp file compilation work successfully

Question:

1) Does it mean that I can not include header file in C with extern «C» function in it??

2) Can I include header within extern»C» like shown below

extern "C" {

#include "abc.h"
#include "...h"
}

3) Can I put c++ functions definitions in header file with extern «C» so that i can call it in C file?

for example

a.cpp ( cpp file)

void test()
{
   std::printf("this is a test function");
}

a.h (header file)

extern "C" {
void test();
}

b_c.c ( c file)

#include "a.h"

void main()
{
  test();
}

Extern «C» problem

Hello,

I’m a a pretty new programmer just beginning to play around with C and C++. I use Linux and am compiling with gcc/g++ 4.3.2 however I’m coming across a strange problem that I just can’t resolve.

I’m trying to write a simple program to just see the possibilities of calling C++ code from C. The main() function is in C :

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
#include <stdlib.h>
#include "cpp_main.h"

/*
 * 
 */
int main(int argc, char** argv) {
    int return_value;
    return_value = cpp_main(argc,argv);
    return (return_value);
}

The function cpp_main() is written in C++, and is in file cpp_main.cpp :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "cpp_main.h"
//#include "testclass.h"

//int cpp_main(int argc, char** argv);
/*extern "C" {
    int cpp_main(int argc, char** argv);
}*/

int cpp_main(int argc, char** argv){
    char *testtext = "Some Test Text to display.\n";
    //TestClass::WriteMessage(testtext);
    
    return(0);
}

And cpp_main.h is :

1
2
3
4
5
6
7
8
9
10
//#ifndef _CPP_MAIN_H
//#define _CPP_MAIN_H

// Declare cpp_main() function
//int cpp_main(int argc, char** argv);
extern "C" {
   void cpp_main(int argc, char** argv);
};

//#endif	/* _CPP_MAIN_H */ 

However when I try to build the executable I receive this error :

cpp_main.h:6: error: expected identifier or ‘(’ before string constant

gcc is telling me there is something wrong with extern «C»… ?!?!!?

If I take the line from the header file and paste it directly into cpp_main.cpp everything compiles and links ok… but why won’t it work with the header file ?

Any help is much appreciated

Steve

I’ll try to guess the problem.

The block
extern «C»
{

}
need not a final semicolon.

You also may use the difinition of the form
extern «C» void cpp_main(int argc, char** argv);
if you declare the only function.

But worse thing is that the definition in the cpp_main.h differs from that in the cpp_main.cpp in the returned type (void vs int).

Also, extern «C» is only defined in C++ compiliers, so if you are compiling with a C compilier, you can’t compile it. Put #ifdef _cplusplus (I think) around it with correct #endif s.

Firedraco :

OK, well as in my original post, can you explain why this compiles :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//#include "cpp_main.h"
//#include "testclass.h"
//=========================================
// Include the header in cpp_main.cpp
//=========================================
//int cpp_main(int argc, char** argv);
extern "C" {
    int cpp_main(int argc, char** argv);
}

int cpp_main(int argc, char** argv){
    char *testtext = "Some Test Text to display.\n";
    //TestClass::WriteMessage(testtext);
    
    return(0);
}

Yet if I separate decelerations into a header file, this does NOT compile, giving the error I originally stated :

cpp_main.h

1
2
3
4
5
6
// Declare cpp_main() function
//int cpp_main(int argc, char** argv);
extern "C" {
   int cpp_main(int argc, char** argv);
};

cpp_main.cpp

1
2
3
4
5
6
7
8
9
#include "cpp_main.h"


int cpp_main(int argc, char** argv){
    char *testtext = "Some Test Text to display.\n";
    //TestClass::WriteMessage(testtext);
    
    return(0);
}

I’m using gcc and it has the capability to determine the source type (C or C++) from the file extension and passes it to the appropriate compiler in the toolchain, therefore I do not believe it’s a problem due to trying to compile C++ with a C compiler.

melkiy:

I was playing round with the return type and forgot to put it back before quoting the code here in the forum. Also it’s not because I didn’t have a semi-colon after the ‘extern’ decleration.

i succeeded in compiling your code with *.h and *.cpp files
with gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)

Are you sure the problem is in compiling (gcc -c cpp_main.cpp), not in linking? Otherwise it’s another problem.

Last edited on

melkiy:

I managed to solve the problem — I had included a C++ header in the C file which contains main() (as you’ll see from my original post)

I had a misunderstanding of the use of headers — I thought they were there to enable the linker to resolve references to functions in other files. I was therefore skeptical at first removing the C++ #include expecting an ‘unresolved function’ error — but no gcc doesn’t necessarily use headers to resolve

Thanks for your help though.. tis much appreciated by a newbie !

Topic archived. No new replies allowed.

My C++ program needs to use an external C library.
Therefore, I’m using the

extern "C"
{
   #include <library_header.h>
}

syntax for every module I need to use.

It worked fine until now.
A module is using the this name for some variables in one of its header file.
The C library itself is compiling fine because, from what I know, this has never been a keyword in C.

But despite my usage of the extern «C» syntax,
I’m getting errors from my C++ program when I include that header file.

If I rename every this in that C library header file with something like _this,
everything seems to work fine.

The question is:

Shouldn’t the extern «C» syntax be enough for backward compatibility,
at least at syntax level, for an header file?
Is this an issue with the compiler?

asked Sep 3, 2014 at 14:10

nyarlathotep108's user avatar

nyarlathotep108nyarlathotep108

5,3052 gold badges26 silver badges65 bronze badges

4

Shouldn’t the extern «C» syntax be enough for backward compatibility, at least at syntax level, for an header file? Is this an issue with the compiler?

No. Extern «C» is for linking — specifically the policy used for generated symbol names («name mangling») and the calling convention (what assembly will be generated to call an API and stack parameter values) — not compilation.

The problem you have is not limited to the this keyword. In our current code base, we are porting some code to C++ and we have constructs like these:

struct Something {
    char *value;
    char class[20]; // <-- bad bad code!
};

This works fine in C code, but (like you) we are forced to rename to be able to compile as C++.

answered Sep 3, 2014 at 14:19

utnapistim's user avatar

6

Strangely enough, many compilers don’t forcibly disallow keyword redefinition through the preprocessor:

#include <iostream>

// temporary redefinition to compile code abusing the "this" keyword
#define cppThis this
#define this thisFunction

int this() {
    return 1020;
}

int that() {
   return this();
}

// put the C++ definition back so you can use it
#undef this
#define this cppThis

struct DumpThat {
    int dump() {
       std::cout << that();
    }
    DumpThat() {
       this->dump();
    }
};

int main ()
{
    DumpThat dt;
}

So if you’re up against a wall, that could let you compile a file written to C assumptions that you cannot change.

It will not—however—allow you to get a linker name of «this». There might be linkers that let you do some kind of remapping of names to help avoid collisions. A side-effect of that might be they allow you to say thisFunction -> this, and not have a problem with the right hand side of the mapping being a keyword.

In any case…the better answer if you can change it is…change it!

Community's user avatar

answered Sep 3, 2014 at 14:41

HostileFork says dont trust SE's user avatar

4

If extern "C" allowed you to use C++ keywords as symbols, the compiler would have to resolve them somehow outside of the extern "C" sections. For example:

extern "C" {
    int * this;  //global variable
    typedef int class;
}


int MyClass::MyFunction() { return *this; }  //what does this mean?
                                             //MyClass could have a cast operator
class MyOtherClass;  //forward declaration or a typedef'ed int?

answered Sep 3, 2014 at 14:36

IronMensan's user avatar

IronMensanIronMensan

6,7611 gold badge26 silver badges35 bronze badges

Could you be more explicit about «using the this name for some variables in one of its header files»?

Is it really a variable or is it a parameter in a function prototype?

If it is the latter, you don’t have a real problem because C (and C++) prototypes identify parameters by position (and type) and the names are optional. You could have a different version of the prototype, eg:

#ifdef __cplusplus
  extern "C" {
   void aFunc(int);
  }
#else
 void aFunc(int this);
#endif

Remember there is nothing magic about header files — they just provide code which is lexically included in at the point of #include — as if you copied and pasted them in.

So you can have your own copy of a library header which does tricks like the above, just becoming a maintenance issue to ensure you track what happens in the original header. If this was likely to become an issue, add a script as a build step which runs a diff against the original and ensures the only point of difference is your workaround code.

answered Sep 3, 2014 at 17:57

Andy Dent's user avatar

Andy DentAndy Dent

17.6k6 gold badges88 silver badges115 bronze badges

This tutorial shows how to resolve the “undefined reference” problem when using both C and C++ code in one project. We will create a basic project, show how to reproduce the “undefined reference” error for a function that is defined in a C file, explain how it happens and show how to solve it in a universal way.

  1. Start Visual Studio and create a project using any of the VisualGDB project wizards. We will show it based on the Embedded wizard, but the same steps will also work for the Linux, Android and Windows wizards:01-externcname
  2. Add a new file called add.h to your project and add the following code there:

    #pragma once

    int add(int a, int b);

  3. Create a new file called add.c (not add.cpp) and provide an implementation for that function. You can use the ‘Create implementation’ command provided by the Clang IntelliSense for simplicity:02-header
  4. Build the project to ensure there are no syntax errors:03-source
  5. Now include the <add.h> file from your main C++ source (if your project has a .c source, change its extension to .cpp). If you build your project now, you will see the following error:

    undefined reference to `add(int, int)

    04-undefined

  6. The error happens at the linking stage, i.e. after each of the source files was compiled to a .o file but before all the .o files are merged into the final executable. To see why exactly this happens we will use the “nm” tool from the GCC toolchain. The tool displays a list of symbols in an object file. Run it on the object file that defines the add() function and the one that uses it:05-namesNote that the add.o file provides a symbol called “add” while the LEDBlink.o file expects a symbol called “_Z3addii” (‘U’ before the names means that the symbol is undefined in this object file and must be defined elsewhere). The difference in the names causes the “undefined reference” error shown above.
  7. The “_Z3addii” is the internal GCC name for ‘function add that takes arguments of type int and int). This name transformation is done automatically to support function overloading. E.g. you can declare another function called ‘add’ that will accept 3 arguments and the code will compile successfully (and stop at linking as before):06-add2
  8. Looking into the new .o file will show that it now expects 2 functions: _Z3addii and _Z3addiii. So the name transformation is needed for the linker to distinguish between those functions:07-sym2
  9. The easiest way to fix this error is to put an extern “C” block around the #include<> statement:08-externc
  10. When a C++ compiler encounters a function defined inside an extern “C” block, it disables the name transformation for it, so it will generate the same name for it as the C compiler would:09-externsym
  11. As a side effect of this, you will not be able to overload the function anymore. Any attempt to declare another function called ‘add’ will result in a compilation error, as the compiler cannot distinguish between those functions without using name transformation that was disabled by extern “C”: 10-conflict
  12. In order to avoid putting extern “C” around the included header files, it is recommended to put this block directly inside them. However putting it unconditionally will prevent the C files from compiling properly:11-externerr
  13. The solution to this is very simple. Use the __cplusplus macro to detect whether the header file is parsed by a C or C++ compiler and only include extern “C” for C++ files:

    #pragma once

    #ifdef __cplusplus

    extern «C»

    {

    #endif

    //place your functions here

    #ifdef __cplusplus    

    }

    #endif

    12-ifdef

  14. Same problem will happen if a .c file tries to call a function defined in a .cpp file without declaring it with extern “C”. If this happens, ensure you have extern “C” in your header file and that the header file is actually included by the .cpp file before the function is defined.

Hello,

I’m a a pretty new programmer just beginning to play around with C and C++. I use Linux and am compiling with gcc/g++ 4.3.2 however I’m coming across a strange problem that I just can’t resolve.

I’m trying to write a simple program to just see the possibilities of calling C++ code from C. The main() function is in C :

Code:

#include <stdio.h>
#include <stdlib.h>
#include "cpp_main.h"

/*
 * 
 */
int main(int argc, char** argv) {
    int return_value;
    return_value = cpp_main(argc,argv);
    return (return_value);
}

The function cpp_main() is written in C++, and is in file cpp_main.cpp :

Code:

#include "cpp_main.h"
//#include "testclass.h"

//int cpp_main(int argc, char** argv);
/*extern "C" {
    int cpp_main(int argc, char** argv);
}*/

int cpp_main(int argc, char** argv){
    char *testtext = "Some Test Text to display.\n";
    //TestClass::WriteMessage(testtext);
    
    return(0);
}

And cpp_main.h is :

Code:

//#ifndef _CPP_MAIN_H
//#define _CPP_MAIN_H

// Declare cpp_main() function
//int cpp_main(int argc, char** argv);
extern "C" {
   void cpp_main(int argc, char** argv);
};

//#endif	/* _CPP_MAIN_H */

However when I try to build the executable I receive this error :

cpp_main.h:6: error: expected identifier or �(� before string constant

gcc is telling me there is something wrong with extern «C»… ?!?!!?

If I take the line from the header file and paste it directly into cpp_main.cpp everything compiles and links ok… but why won’t it work with the header file ?

Any help is much appreciated

Steve

Понравилась статья? Поделить с друзьями:
  • Explay l80 ошибка формата
  • Ext4 проверка и исправление ошибок
  • F006 ошибка стиральной машины индезит
  • Expression expected ошибка vba
  • Express ошибка 500