开发者

Is it required to add 'extern C' in source file also?

I found some code recently where extern "C" was added in source file also for functions. They were also added in the header files where they were declared.

I was under the assumption that adding 'extern "开发者_如何学编程C" in header files was sufficient.

Where should extern "C" blocks be added?

UPDATE: Suppose I am compiling my C code using a CPP compiler and have added extern "C" guards for all the functions in header files (i.e. all my functions have their prototypes in headers), but in source files I have not added the same. Will this cause a problem?


Since you mean

extern "C" { ... }

style guards, these declare some functions to be of "C" linkage, rather than "C++" linkage (which typically has a bunch of extra name decoration to support things like overloaded functions).

The purpose, of course, is to allow C++ code to interface with C code, which is usually in a library. If the library's headers weren't written with C++ in mind, then they won't include the extern "C" guards for C++.

A C header written with C++ in mind will include something along the lines of

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

to make sure C++ programs see the correct linkage. However, not all libraries were written with C++ in mind, so sometimes you have to do

extern "C" {
#include "myclibrary.h"
}

to get the linkage correct. If the header file is provided by someone else then it's not good practice to change it (because then you can't update it easily), so it's better to wrap the header file with your own guard (possibly in your own header file).

extern "C" isn't (AFAIK) ANSI C, so can't be included in normal C code without the preprocessor guards.

In response to your edit:

If you are using a C++ compiler, and you declare a function as extern "C" in the header file, you do not need to also declare that function as extern "C" in the implementation file. From section 7.5 of the C++ standard (emphasis mine):

If two declarations of the same function or object specify different linkage-specifications (that is, the linkage-specifications of these declarations specify different string-literals), the program is ill-formed if the declarations appear in the same translation unit, and the one definition rule applies if the declarations appear in different translation units. Except for functions with C++ linkage, a function declaration without a linkage specification shall not precede the first linkage specification for that function. 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 function declaration.

I'm not convinced it's good practice though, since there's the potential for the linkage specifications to diverge by accident (if, for example, the header file containing the linkage specification isn't included in the implementing file). I think it's better to be explicit in the implementation file.


They only need to go in anything that is included by other source files.

With some idioms you'll find people including source files.


They should be added to all files, that get included in other files.

Normally, one doesn't include source files.


Apologia

The question has changed to be much clearer what it was asking about. This answer addressed the original question, when it was at least debatable whether it was discussing guards against multiple inclusion in header files - which is what my answer addresses. Clearly, if the question had been as clear then as it is now, I would not have submitted this answer.


Original answer

No, it is not necessary to include the guards in the C code too.

If the header file 'header.h' says:

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED
...
#endif

Then it is perfectly safe for a source file 'source.c' to say:

#include "header.h"

It is also safe for other headers to include 'header.h'.

However, people note that opening a header file and reading it takes time, which slows up a compilation, so sometimes people do things like:

#ifndef HEADER_H_INCLUDED
#include "header.h"
#endif

This means that if some other header included in 'source.c' has already included 'header.h', then the '#include' is not re-processed. (Or, if 'header.h' has already been included directly in 'source.c', though that's a silly buglet.)

So, when encountered, it is likely to be an attempt to optimize the compilation performance. It is far from clear that it buys you much; modern C preprocessors are fairly intelligent about the issue and will avoid re-including the file if they can. And there's always a risk that the test in 'source.c' has a typo (#ifndef HEARER_H_INCLUDED, perhaps) in which case the test slows the compilation because the preprocessor tests the irrelevant condition and then proceeds to include 'header.h' after all. It is 'safe'; the header is itself protected-- or should be.

If you see the code in 'source.c' also doing '#define HEADER_H_INCLUDED', then there are problems. The #define has to be either before or after the #include, and neither is good as a general technique.

  • If 'source.c' does '#define HEADER_H_INCLUDED' before including 'header.h', then if the guard appears in 'header.h', the contents of the header will not be included. If the guard does not appear in 'header.h', then things work OK.
  • If 'source.c' does '#define HEADER_H_INCLUDED' after including 'header.h', then if the guard appears in 'header.h', we get a benign redefinition of HEADER_H_INCLUDED. If 'header.h' does not contain the guard but does include a file which includes 'header.h', you are not protected from multiple inclusion after all.

Note that body of the header appears after the '#define HEADER_H_INCLUDED'. This is again protection if nested includes include 'header.h'.


You mean the 'extern c' preprocessors? They have to be on the function definition as well as that affects how the function call is stored in the compiled binary. Its only really needed if you are linking compiled c++ together with c which is compiled as C (as opposed to c in a .cpp file).


The "C" guards have two purposes:

  1. When your code is compiled, the functions will be exported in a way that will allow a non C++ compiler/linker to use them (no C++ name mangling etc.)
  2. When a C++ compiler uses your header files, it will know that it should bind the symbols in the C way which in turn will make sure that the resulting program will link successfully. They don't carry a meaning for a non C++ compiler but since the symbols were generated in C-style in (1) this is the desired effect.

Since you include the header with the "C" guards also in your implementation file, the information on how the symbols should be created at compile time is available to the compiler and the compiler will create the symbols in a way that can be used by a non C++ compiler. Consequently you only need to specify extern "C" in your header file as long as the header file is also included by the implementation file.


it is not required for extern to be used in source files, if they are used in the header file and that file is included by the rest of the source files.

As far as I remember the standard, all function declarations are considered as "extern" by default, so there is no need to specify it explicitly. That doesn't make this keyword useless since it can also be used with variables (and it that case - it's the only solution to solve linkage problems). But with the functions - yes, it's optional.

A little more verbose answer is that it allows you to use variables compiled in another source code file, but doesn't reserve memory for the variable. So, to utilise extern, you have to have a source code file or a library unit that contains memory space for the variable on the top level (not within functions). Now, you can refer to that variable by defining an extern variable of the same name in your other source code files.

In general, the use of extern definition should be avoided. They lead easily to unmanagable code and errors that hard to locate. Of course, there are examples where other solutions would be impractical, but they are rare. For example, stdin and stdout are macros that are mapped to an extern array variable of type FILE* in stdin.h; memory space for this array is in a standard C-library unit.


We had always only added extern "C" to the header definitions, but this allows the C++ code to implement the function with a different signature via overloading without errors and yet it doesn't mangle the symbol definition so at link times it uses this mismatching function. If the header and the definition both have extern "C" then a mismatched signature generates an error with Visual Studio 2017 and with g++ 5.4.

This following code compiles without an error for Visual Studio 2017 and g++ 5.4

extern "C" {
    int test(float a, int b);
}
int test(int b)
{
    return b;
}

It seems that gcc mangles the symbol name in this case but Visual Studio 2017 does not.

However including the extern "C" with the definition catches the mismatch at compile time.

extern "C" {
    int test(float a, int b);
}
extern "C" int test(int b)
{
    return b;
}

gives the following error on g++:

 g++ -c -o test.o test.cpp
 test.cpp: In function ‘int test(int)’:
 test.cpp:4:26: error: conflicting declaration of C function ‘int test(int)’
 extern "C" int test(int b)
                      ^
 test.cpp:2:9: note: previous declaration ‘int test(float, int)’
 int test(float a, int b);

or with cl

cl /c test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27042 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

test.cpp
test.cpp(4): error C2733: 'test': second C linkage of overloaded function not allowed
test.cpp(2): note: see declaration of 'test'
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜