6

I am working on a project in which some people have already written code in C++ and we have to use it in our code in C. So I have tried following test to write a test program which demonstrates the same:

The header file is:

 #ifndef h_files_n
    #define h_files_n

    #include<iostream>

    #ifdef __cplusplus
        extern "C" {
    #endif

    void add_func(int, int);

    #ifdef __cplusplus
        }
    #endif

    #endif

cpp file is :

#include"h_files.h"

void add_func(int num, int nums)
{
    std :: cout << "The addition of numbers is : "<< num+nums << std endl;
}

The c file is :

#include<stdio.h>
#include"h_files.h"

int main()
{
    printf("We are calling the C function form C++ file.\n");

    add_func(10,15);

    return 0;
}

makefile is :

CC = gcc
inc = -I include

vpath %.c src
vpath %.cpp src
vpath %.o obj

all : $(addprefix obj/,functions.o main.o) run

run : main.o functions.o
    $(CC) -o bin/$@ $^

obj/%.o : %.cpp
    $(CXX) -c $(inc) $^ -o $@ -libstdc++

obj/%.o : %.c
    $(CC) -c $(inc) $^ -o $@

.PHONY : clean

clean :
    -rm -f obj/* bin/*

I am getting the following error:

g++ -c -I include src/functions.cpp -o obj/functions.o
gcc -c -I include src/main.c -o obj/main.o
gcc -o bin/run obj/main.o obj/functions.o
obj/functions.o: In function `add_func':
functions.cpp:(.text+0x1e): undefined reference to `std::cout'
functions.cpp:(.text+0x23): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
functions.cpp:(.text+0x2d): undefined reference to `std::ostream::operator<<(int)'
functions.cpp:(.text+0x32): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
functions.cpp:(.text+0x3a): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
obj/functions.o: In function `__static_initialization_and_destruction_0(int, int)':
functions.cpp:(.text+0x68): undefined reference to `std::ios_base::Init::Init()'
functions.cpp:(.text+0x77): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
make: *** [run] Error 1
  • If I use g++ as linker then It works fine. But gcc linker gives me the problem.
  • As I think of the problem is the function name mangling by g++ and gcc does not mangles the functions name(symbols).
  • So is there any compiler flag that would avoid name mangling if possible.
  • The reason for avoiding g++ linker is It treats the linking as C++ style but the base code is in C so It may introduce some bug in calling code.

Please somebody suggest the solution.

7
  • You can't use cout in a C program. Commented Apr 7, 2015 at 17:48
  • I would try using g++ in the link stage: g++ -o bin/run obj/main.o obj/functions.o Commented Apr 7, 2015 at 17:50
  • 1
    @Barmar That's not entirely true, and out of question here. Commented Apr 7, 2015 at 17:55
  • @KhouriGiordano Right, but not of interest. The sourcefile with the function definition is compiled as c++ source. Commented Apr 7, 2015 at 17:56
  • 3
    What actual bugs have you encountered (when linking with g++)? What are you afraid of? Commented Apr 10, 2015 at 9:46

5 Answers 5

10

$(CC) -o bin/$@ $^

Use

run : main.o functions.o
    $(CXX) -o bin/$@ $^

instead to link everything together using the g++ linker, and have the defaults for the linked libstc++.a library set automatically.

Otherwise you'll need to specify -lstc++ as additional library explicitely.


Also if you're designing a pure c-API for your c++ code you should have the

 #include <iostream>

statement in the functions.cpp source file only. Remove c++ standard headers from functions.h.


Please don't use using namespace std; in c++ header files generally. It's prone to invoke namespace clashes of all unexpected kinds (no one knows about all of the names used in the namespace std).

It should not appear in a pure c-API header file anyway.


If you want to have a mixed c/c++ API header file, put all of the c++ specific statements within the c++ guards:

 #ifdef __cplusplus
 #include<iostream>

 class xyz; // A c++ forward declaration
 #endif
Sign up to request clarification or add additional context in comments.

Comments

6

You should either link program by g++ or manually specify libstdc++ library(ies).

5 Comments

Linking to g++ may introduce some bug as it links the code in C++ way but the calling code is in C.
@AbhijatyaSingh: What sort of bug do you envisage this causing? As long as the calling conventions and mangled symbol names match between translation units (and, if they don't, the link will fail), it doesn't really matter what language each unit is written in.
@AbhijatyaSingh If you were right, it would be impossible to link a program that used both C and C++ code. Since that's clearly possible, you must be wrong. On sensible platforms like yours, C++ linking is either identical to, or a superset of, C linking.
@AbhijatyaSingh The truth is that neither gcc nor g++ do any linking operation. They both translates their options into a new options list for the real linker ld and invoke it on the object files.
@fjardon: you are forgetting the importance and role of collect2 at linking stage.
2

The reason for avoiding g++ linker is It treats the linking as C++ style but the base code is in C so It may introduce some bug in calling code

That's simply not true.

By the time you get to the link stage, the difference between C and C++ is largely academic: you're linking objects in machine code, not C or C++ programs.

What you do need to be aware of is calling conventions and mangled names, but if that introduces an incompatibility in your program then you'll know about it at link-time. It won't introduce silent bugs unless something is very, very wrong.

So, "it may introduce some bug in calling code" is wrong and you may go ahead and link with g++ like everybody else does. :) Because the only other difference with your C++ code is that it is referencing the standard library and C++ runtime, which you simply cannot do without.

Comments

2

If I use g++ as linker then It works fine. But gcc linker gives me the problem.

That's why you should use g++.

As I think of the problem is the function name mangling by g++ and gcc does not mangles the functions name(symbols).

When compiling C++ code, name mangling is used. When compiling C code, name mangling is not used. This has nothing to do with linking which doesn't care whether the symbols have mangled names or not.

So is there any compiler flag that would avoid name mangling if possible.

That question is based on the false assumption that name mangling has anything to do with linking.

The reason for avoiding g++ linker is It treats the linking as C++ style but the base code is in C so It may introduce some bug in calling code.

The linker doesn't care about the language the code was originally written in. It just links the compiled code.

If C code had to be linked differently from C++ code or there would be some possible bug, then what you are attempting to do would be impossible -- there would be no way to link the final executable. But since we all know C and C++ code can be linked together safely on sensible platforms like yours, you must be worried about problems that don't exist.

Comments

2

You generally should link your C program using a C++ library with a C++ compiler (like g++), and you very probably need to link the standard C++ library. Be (otherwise) careful about:

  • static or global data which needs some non-trivial C++ constructor (e.g. std::cout) - which conceptually should be run before entering your C main function. See also GCC function attributes, notably constructor and visibility attributes.
  • C++ functions throwing exceptions which are not caught by C++ code. If your C program calls a C++ function which throws an exception which is not caught, you could be in trouble.... (probable undefined behavior, or premature termination). This may happen when new is invoked in an out-of-memory process.
  • C++ functions returning non POD aggregate (but you'll have trouble in declaring such a function on the C side; declaring a C struct with all the data member fields of the C++ struct won't be always enough or correct, because the C++ type requires its destructor to be called, and because it may add some vtable pointer, etc...)
  • name mangling and calling conventions. You probably should declare every C++ function visible by C code as extern "C"

Stricto sensu, C++ is designed to be interoperable with a subset of C, but not the converse.

Perhaps compiling your C code with a C++ compiler (and fixing all the incompatibilities) -e.g. with g++ -std=c++11 -Wall -Wextra -g ...- could be easier. If your C code base is small (less than 100K source lines), you could even consider porting it to C++, and progressively using C++ idiomatically. Be aware that C++11 and C11 (or C99) are different languages (which happen to have some limited and partial compatibility).

In practice, link using g++. In almost every cases, this won't add bugs. If it does, compile all your code using g++ and rename all your C source files as C++ files (e.g. your .c file suffix becoming .cc) and recompile the whole thing as C++ (of course by correcting your "C" program till it makes the C++ compiler happy).

3 Comments

Sir !!!!! Thats why I want to avoid g++ linker because there may be some c++ specific code that while calling in C can cause bug due to C++ way of doing linkage.
On the contrary, you should not avoid linking with g++, but you are nearly required to link with g++
@AbhijatyaSingh: Sir !!!!! You have yet to explain why you think this "can cause bug". We disagree.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.