Combining C++ and C - how does #ifdef __cplusplus work?
2014-12-19 14:06
645 查看
103down votefavorite 62 | I'm working on a project that has a lot of legacy C code. We've started writing in C++, with the intent to eventually convert the legacy code, as well. I'm a little confused about how the C and C++ interact. I understand that by wrapping the C code with extern "C"the C++ compiler will not mangle the C code's names, but I'm not entirely sure how to implement this. So, at the top of each C header file (after the include guards), we have [code]#ifdef __cplusplus extern "C" { #endif and at the bottom, we write [code]#ifdef __cplusplus } #endif In between the two, we have all of our includes, typedefs, and function prototypes. I have a few questions, to see if I'm understanding this correctly: If I have a C++ file A.hh which includes a C header file B.h, includes another C header file C.h, how does this work? I think that when the compiler steps into B.h, __cpluspluswill be defined, so it will wrap the code with extern "C"(and __cpluspluswill not be defined inside this block). So, when it steps into C.h, __cpluspluswill not be defined and the code will not be wrapped in extern "C". Is this correct? Is there anything wrong with wrapping a piece of code with extern "C" { extern "C" { .. } }? What will the second extern "C"do? We don't put this wrapper around the .c files, just the .h files. So, what happens if a function doesn't have a prototype? Does the compiler think that it's a C++ function? We are also using some third-party code which is written in C, and does not have this sort of wrapper around it. Any time I include a header from that library, I've been putting an extern "C"around the #include. Is this the right way to deal with that? Finally, is this set up a good idea? Is there anything else we should do? We're going to be mixing C and C++ for the foreseeable future, and I want to make sure we're covering all our bases. c++ c preprocessor
| ||||||||
a comment |
3 Answers
activeoldestvotesup vote91down voteaccepted | extern "C"doesn't really change the way that the compiler reads the code.If your code is in a .c file, it will be compiled as C, if it is in a .cpp file, it will be compiled as C++ (unless you do something strange to your configuration). What extern "C"does is affect linkage. C++ functions, when compiled, have their names mangled -- this is what makes overloading possible. The function name gets modified based on the types and number of parameters, so that two functions with the same name will have different symbol names. Code inside an extern "C"is still C++ code. There are limitations on what you can do in an extern "C" block, but they're all about linkage. You can't define any new symbols that can't be built with C linkage. That means no classes or templates, for example. extern "C"blocks nest nicely. There's also extern "C++"if you find yourself hopelessly trapped inside of extern "C"regions, but it isn't such a good idea from a cleanliness perspective. Now, specifically regarding your numbered questions: Regarding #1: __cplusplus should be defined inside of extern "C"blocks. This doesn't matter, though, since the blocks should nest neatly. Regarding #2: __cplusplus will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file. The same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C"when being interpreted as C++, and they should not have extern "C"when being interpreted as C -- hence the #ifdef __cpluspluschecking. To answer your question #3: functions without prototypes will have C++ linkage if they are in .cpp files and not inside of an extern "C"block. This is fine, though, because if it has no prototype, it can only be called by other functions in the same file, and then you don't generally care what the linkage looks like, because you aren't planning on having that function be called by anything outside the same compilation unit anyway. PS:也就是说cpp里的函数,如果没有被其他.c文件的调用不需要在前面加extern "C",如果该函数需要被其他.c文件调用,则需要在.cpp文件里的函数实现上加上extern "C" //xxx.cpp的实现 extern "C" void C_fun() { } For #4, you've got it exactly. If you are including a header for code that has C linkage (such as code that was compiled by a C compiler), then you must extern "C"the header -- that way you will be able to link with the library. (Otherwise, your linker would be looking for functions with names like _Z1hicwhen you were looking for void h(int, char) 5: This sort of mixing is a common reason to use extern "C", and I don't see anything wrong with doing it this way -- just make sure you understand what you are doing. |
103down votefavorite 62 | I'm working on a project that has a lot of legacy C code. We've started writing in C++, with the intent to eventually convert the legacy code, as well. I'm a little confused about how the C and C++ interact. I understand that by wrapping the C code with extern "C"the C++ compiler will not mangle the C code's names, but I'm not entirely sure how to implement this. So, at the top of each C header file (after the include guards), we have [code]#ifdef __cplusplus extern "C" { #endif and at the bottom, we write [code]#ifdef __cplusplus } #endif In between the two, we have all of our includes, typedefs, and function prototypes. I have a few questions, to see if I'm understanding this correctly: If I have a C++ file A.hh which includes a C header file B.h, includes another C header file C.h, how does this work? I think that when the compiler steps into B.h, __cpluspluswill be defined, so it will wrap the code with extern "C"(and __cpluspluswill not be defined inside this block). So, when it steps into C.h, __cpluspluswill not be defined and the code will not be wrapped in extern "C". Is this correct? Is there anything wrong with wrapping a piece of code with extern "C" { extern "C" { .. } }? What will the second extern "C"do? We don't put this wrapper around the .c files, just the .h files. So, what happens if a function doesn't have a prototype? Does the compiler think that it's a C++ function? We are also using some third-party code which is written in C, and does not have this sort of wrapper around it. Any time I include a header from that library, I've been putting an extern "C"around the #include. Is this the right way to deal with that? Finally, is this set up a good idea? Is there anything else we should do? We're going to be mixing C and C++ for the foreseeable future, and I want to make sure we're covering all our bases. c++ c preprocessor
| ||||||||
a comment |
3 Answers
activeoldestvotesup vote91down voteaccepted | extern "C"doesn't really change the way that the compiler reads the code. If your code is in a .c file, it will be compiled as C, if it is in a .cpp file, it will be compiled as C++ (unless you do something strange to your configuration). What extern "C"does is affect linkage. C++ functions, when compiled, have their names mangled -- this is what makes overloading possible. The function name gets modified based on the types and number of parameters, so that two functions with the same name will have different symbol names. Code inside an extern "C"is still C++ code. There are limitations on what you can do in an extern "C" block, but they're all about linkage. You can't define any new symbols that can't be built with C linkage. That means no classes or templates, for example. extern "C"blocks nest nicely. There's also extern "C++"if you find yourself hopelessly trapped inside of extern "C"regions, but it isn't such a good idea from a cleanliness perspective. Now, specifically regarding your numbered questions: Regarding #1: __cplusplus should be defined inside of extern "C"blocks. This doesn't matter, though, since the blocks should nest neatly. Regarding #2: __cplusplus will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file. The same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C"when being interpreted as C++, and they should not have extern "C"when being interpreted as C -- hence the #ifdef __cpluspluschecking. To answer your question #3: functions without prototypes will have C++ linkage if they are in .cpp files and not inside of an extern "C"block. This is fine, though, because if it has no prototype, it can only be called by other functions in the same file, and then you don't generally care what the linkage looks like, because you aren't planning on having that function be called by anything outside the same compilation unit anyway. For #4, you've got it exactly. If you are including a header for code that has C linkage (such as code that was compiled by a C compiler), then you must extern "C"the header -- that way you will be able to link with the library. (Otherwise, your linker would be looking for functions with names like _Z1hicwhen you were looking for void h(int, char) 5: This sort of mixing is a common reason to use extern "C", and I don't see anything wrong with doing it this way -- just make sure you understand what you are doing. |
相关文章推荐
- In C++, what’s a vtable and how does it work?
- angular this vs $scope (How does 'this' and $scope work in AngularJS controllers?)
- Android 4.2 Feature Highlight: So, What Is This Miracast Thing And How Does It Work, Anyway?
- SCAN listener and Node listener – How does it work
- What is a GPU and how does it work?
- How Does Proxy ARP Work? And arp secured-arp?
- What is SMS and how does it work?
- 安装ipython,使用scrapy shell来验证xpath选择的结果 | How to install iPython and how does it work with Scrapy Shell
- Openerp: How does notifications, Inbox, To:Me, and Todo mailboxes work?
- How does ASM work with RAID where striping and mirroring are already built-in [ID 330398.1]
- 802.11 WDS how does it work, when to use it and what are the limitations
- [POST] What Is the Linux fstab File, and How Does It Work?
- How does XVCL work?
- How to get Expression Encoder to work with the latest Apple QuickTime (7.64.17.0 and greater)
- How does Google Map My Location work?(转载)
- HOW AND WHY SOCKS v666 PROXY NETWORKS WORK
- C++大学教程(第二版)c++how to program Second Edition --电子工业出版社【美】harvey M.Deitel and paul James Deitel(更新中)
- Perl work tips and how to install perl on various platform
- How does Google Map My Location work?
- How to show a modal dialog and modeless dialog using C++ - 如何用C++显示一个模态对话框和一个非模态对话框