4

I am reading C++ primer and I'm on chapter 19. External linkage.

So for example if I want to link to a C function from C++ then I declare that function as external "C" void foo(); then when I compile my C++ program I issue something like:

gcc -c foo.c && g++ main.cxx foo.o -o prog

This works just fine and I can on the other hand export my C++ code to C for example.

  • But as long as a C++ compiler can compile directly C code, why I bother declare it as external and why I need to use gcc to compile that source?

Here is just my simulation of string.h:

// my_string.h
#ifndef MY_STRING_H_
#define MY_STRING_H_

#ifdef __cplusplus
    extern "C" {
#endif

    int my_strlen(char const*);
    int my_strcpy(char*, char const*);
    int my_strcmp(char const*, char const*);

#ifdef __cplusplus
    }

#endif
#endif

// my_string.c
#include "my_string.h"

int my_strlen(char const* cp){
   int sz = 0;
   for(char const* tmp = cp; *tmp; tmp++)
      ++sz;

   return sz;
}

int my_strcpy(char* buff, char const* cp){
    
   int i = 0;
   for(int sz = my_strlen(cp); i != sz; ++i)
      *(buff + i) = *(cp + i);

   return i;
}

int my_strcmp(char const* str1, char const* str2){

   int len1 = my_strlen(str1);
   int len2 = my_strlen(str2);

   if(len1 > len2)
      return 1;
   else if(len1 < len2)
      return -1;
   else
      return 0;
}

// main.cxx
#include "my_string.h"
#include <iostream>

int main(){

   std::cout << my_strlen("Ahmed") << '\n';
   char name[10];
   my_strcpy(name, "Ahmed");

   std::cout << name << '\n';
}
  • When I compile my code I issue:

    gcc -c my_string.c && g++ main.cxx my_string.o -o prog
    

It works just fine but If I remove extern "C" frome the header and I compile all the code as a C++ code it works fine too:

  g++ my_string.c main.cxx -o prog
  • I've remove extern "C" from the header my_string.h and works fine. So Why I need to link externally to C code as long as C++ supports it?
user438383
  • 5,716
  • 8
  • 28
  • 43
Itachi Uchiwa
  • 3,044
  • 12
  • 26
  • 2
    A C++ compiler cannot compile all C code, it's very easy to write C code that won't compile in C++ – UnholySheep Sep 08 '21 at 21:31
  • 5
    Your reasoning is correct: If all sources are under your control, and if the C sources are using only the C subset that is also a C++ subset, you can simply compile everything as C++ and be done. But think about the situation where you are using or providing libraries from or to others. Then you need interoperability. – Peter - Reinstate Monica Sep 08 '21 at 21:32
  • 1
    Or behaves differently between the two languages. Different interpretations of `auto` for example. – user4581301 Sep 08 '21 at 21:32
  • 1
    Use `nm` to look at the function names in each case. – stark Sep 08 '21 at 21:33
  • 2
    *"If I remove `extern "C"` frome the header and I compile all the code as a `C++` code it works fine too"* -- note that you mentioned two steps: 1) remove `extern "C"` and 2) compile as C++. You've got a case where you can do both, or you can do neither, but you get a problem if you do only one. I'm going to propose a duplicate, but let us know if that does not provide the right information to answer your question. – JaMiT Sep 08 '21 at 21:41
  • 1
    See https://stackoverflow.com/questions/1201593/where-is-c-not-a-subset-of-c for lots of examples of valid C code which is not valid C++ (or doesn't do the same thing), and therefore won't be "supported" by a C++ compiler. – Nate Eldredge Sep 08 '21 at 21:53
  • 1
    @Nate Eldredge so it turns out that C is not a subset of C++? Or if it is then what is the definition of one language being a subset of another ? – ampawd Sep 08 '21 at 23:00
  • 1
    The two languages are both changing over time and neither have a requirement to support the other language's features. – drescherjm Sep 09 '21 at 00:18
  • 2
    This comes down to name mangling used for the symbols of both languages. C doesn't support function overloading, so it's assumed that the "my_strlen" symbol can only appear once in a lib/binary, and it will be the untangled name: "my_strlen". C++ allows for different overloads of "my_strlen", and so C++ will encode the input arg types into the name, and whether the method is a member, static, virtual, etc. So "my_strlen" would be translated to something like "_Zn763my_strlen8923ds". – robthebloke Sep 09 '21 at 01:00
  • 2
    the C language by default will only be looking for the C naming convention. The C++ language by default will try to link against the mangled name version. Adding extern "C" causes C++ to assume a C naming convention in the symbol name when linking. You don't technically need this, you could provide a C header with the prototypes that match the C++ naming convention, and the linker would resolve it correctly. However doing this is not going to make your code particularly readable, so we typically just use extern "C" instead.... – robthebloke Sep 09 '21 at 01:03
  • 2
    @ampawd: The usual definition of "subset" would be that "every valid C program is a valid C++ program with the same behavior". And that is definitely not true, and I'm not sure that it ever was; maybe in the very earliest days of C++, but not anytime recently. "C is a subset of C++" is a common misconception. – Nate Eldredge Sep 09 '21 at 02:42

0 Answers0