.c和.cpp混合使用

[32] How to mix C and C++ Updated!
(Part of C++ FAQ, Copyright© 1991-2010, Marshall Cline, cline@parashift.com)

FAQs in section [32]:


[32.1] What do I need to know when mixing C and C++ code?

Here are some high points (though some compiler-vendors might not require all these; check with your compiler-vendor's documentation):

  • You must use your C++ compiler when compiling main() (e.g., for static initialization)
  • Your C++ compiler should direct the linking process (e.g., so it can get its special libraries)
  • Your C and C++ compilers probably need to come from same vendor and have compatible versions (e.g., so they have the same calling conventions)

In addition, you'll need to read the rest of this section to find out how to make your C functions callable by C++ and/or your C++ functions callable by C.

BTW there is another way to handle this whole thing: compile all your code (even your C-style code) using a C++ compiler. That pretty much eliminates the need to mix C and C++, plus it will cause you to be more careful (and possibly —hopefully!— discover some bugs) in your C-style code. The down-side is that you'll need to update your C-style code in certain ways, basically because the C++ compiler is more careful/picky than your C compiler<!--rawtext:[6.11]:rawtext-->. The point is that the effort required to clean up your C-style code may be less than the effort required to mix C and C++, and as a bonus you get cleaned up C-style code. Obviously you don't have much of a choice if you're not able to alter your C-style code (e.g., if it's from a third-party).

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.2] How can I include a standard C header file in my C++ code?

To #include a standard header file (such as <cstdio>), you don't have to do anything unusual. E.g.,

//ThisisC++code

#include<cstdio>
//Nothingunusualin#includeline

intmain()
{
std::printf("Helloworld/n");
//Nothingunusualinthecalleither
...
}

If you think the std:: part of the std::printf() call is unusual, then the best thing to do is "get over it." In other words, it's the standard way to use names in the standard library, so you might as well start getting used to it now.

However if you are compiling C code using your C++ compiler, you don't want to have to tweak all these calls from printf() to std::printf(). Fortunately in this case the C code will use the old-style header <stdio.h> rather than the new-style header <cstdio>, and the magic of namespaces will take care of everything else:

/*ThisisCcodethatI'mcompilingusingaC++compiler*/

#include<stdio.h>
/*Nothingunusualin#includeline*/

intmain()
{
printf("Helloworld/n");
/*Nothingunusualinthecalleither*/
...
}

Final comment: if you have C headers that are not part of the standard library, we have somewhat different guidelines for you. There are two cases: either you can't change the header<!--rawtext:[32.3]:rawtext-->, or you can change the header<!--rawtext:[32.4]:rawtext-->.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.3] How can I include a non-system C header file in my C++ code?

If you are including a C header file that isn't provided by the system, you may need to wrap the #include line in an extern "C" { /*...*/ } construct. This tells the C++ compiler that the functions declared in the header file are C functions.

//ThisisC++code

extern"C"{
//Getdeclarationforf(inti,charc,floatx)
#include"my-C-code.h"
}

intmain()
{
f(7,'x',3.14);
//Note:nothingunusualinthecall
...
}

Note: Somewhat different guidelines apply for C headers provided by the system (such as <cstdio>)<!--rawtext:[32.2]:rawtext--> and for C headers that you can change<!--rawtext:[32.4]:rawtext-->.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.4] How can I modify my own C header files so it's easier to #include them in C++ code?

If you are including a C header file that isn't provided by the system, and if you are able to change the C header, you should strongly consider adding the extern "C" {...} logic inside the header to make it easier for C++ users to #include it into their C++ code. Since a C compiler won't understand the extern "C" construct, you must wrap the extern "C" { and } lines in an #ifdef so they won't be seen by normal C compilers.

Step #1: Put the following lines at the very top of your C header file (note: the symbol __cplusplus is #defined if/only-if the compiler is a C++ compiler):

#ifdef__cplusplus
extern"C"{
#endif

Step #2: Put the following lines at the very bottom of your C header file:

#ifdef__cplusplus
}
#endif

Now you can #include your C header without any extern "C" nonsense in your C++ code:

//ThisisC++code

//Getdeclarationforf(inti,charc,floatx)
#include"my-C-code.h"
//Note:nothingunusualin#includeline

intmain()
{
f(7,'x',3.14);
//Note:nothingunusualinthecall
...
}

Note: Somewhat different guidelines apply for C headers provided by the system (such as <cstdio>)<!--rawtext:[32.2]:rawtext--> and for C headers that you can't change<!--rawtext:[32.3]:rawtext-->.

Note: #define macros are evil<!--rawtext:[6.15]:rawtext--> in 4 different ways: evil#1<!--rawtext:[9.5]:rawtext-->, evil#2<!--rawtext:[39.4]:rawtext-->, evil#3<!--rawtext:[39.5]:rawtext-->, and evil#4<!--rawtext:[39.6]:rawtext-->. But they're still useful sometimes<!--rawtext:[6.16]:rawtext-->. Just wash your hands after using them.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.5] How can I call a non-system C function f(int,char,float) from my C++ code?

If you have an individual C function that you want to call, and for some reason you don't have or don't want to #include a C header file in which that function is declared, you can declare the individual C function in your C++ code using the extern "C" syntax. Naturally you need to use the full function prototype:

extern"C"voidf(inti,charc,floatx);

A block of several C functions can be grouped via braces:

extern"C"{
voidf(inti,charc,floatx);
intg(char*s,charconst*s2);
doublesqrtOfSumOfSquares(doublea,doubleb);
}

After this you simply call the function just as if it were a C++ function:

intmain()
{
f(7,'x',3.14);
//Note:nothingunusualinthecall
...
}

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.6] How can I create a C++ function f(int,char,float) that is callable by my C code?

The C++ compiler must know that f(int,char,float) is to be called by a C compiler using the extern "C" construct<!--rawtext:[32.3]:rawtext-->:

//ThisisC++code

//Declaref(int,char,float)usingextern"C":
extern"C"voidf(inti,charc,floatx);

...

//Definef(int,char,float)insomeC++module:
voidf(inti,charc,floatx)
{
...
}

The extern "C" line tells the compiler that the external information sent to the linker should use C calling conventions and name mangling (e.g., preceded by a single underscore). Since name overloading isn't supported by C, you can't make several overloaded functions simultaneously callable by a C program.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.7] Why is the linker giving errors for C/C++ functions being called from C++/C functions?

If you didn't get your extern "C" right, you'll sometimes get linker errors rather than compiler errors. This is due to the fact that C++ compilers usually "mangle" function names (e.g., to support function overloading) differently than C compilers.

See the previous two FAQs on how to use extern "C".

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.8] How can I pass an object of a C++ class to/from a C function? Updated!

[Recently rewrote prose to clarify issues surrounding different binary representations for Base* and Derived* (in 8/10). Click here to go to the next FAQ in the "chain" of recent changes<!--rawtext:[33.5]:rawtext-->.]

Here's an example (for info on extern "C", see the previous two FAQs).

Fred.h:

/*ThisheadercanbereadbybothCandC++compilers*/
#ifndefFRED_H
#defineFRED_H

#ifdef__cplusplus
classFred{
public:
Fred();
voidwilma(int);
private:
inta_;
};
#else
typedef
structFred
Fred;
#endif

#ifdef__cplusplus
extern"C"{
#endif

#ifdefined(__STDC__)||defined(__cplusplus)
externvoidc_function(Fred*);
/*ANSICprototypes*/
externFred*cplusplus_callback_function(Fred*);
#else
externvoidc_function();
/*K&Rstyle*/
externFred*cplusplus_callback_function();
#endif

#ifdef__cplusplus
}
#endif

#endif
/*FRED_H*/

Fred.cpp:

//ThisisC++code

#include"Fred.h"

Fred::Fred():a_(0){}

voidFred::wilma(inta){}

Fred*cplusplus_callback_function(Fred*fred)
{
fred->wilma(123);
returnfred;
}

main.cpp:

//ThisisC++code

#include"Fred.h"

intmain()
{
Fredfred;
c_function(&fred);
...
}

c-function.c:

/*ThisisCcode*/

#include"Fred.h"

voidc_function(Fred*fred)
{
cplusplus_callback_function(fred);
}

Unlike your C++ code, your C code will not be able to tell that two pointers point at the same object unless the pointers are exactly the same type. For example, in C++ it is easy to check if a Derived* called dp points to the same object as is pointed to by a Base* called bp: just say if (dp == bp) .... The C++ compiler automatically converts both pointers to the same type, in this case to Base*, then compares them. Depending on the C++ compiler's implementation details, this conversion sometimes changes the bits of a pointer's value.

(Technical aside: Most C++ compilers use a binary object layout that causes this conversion to happen with multiple inheritance<!--rawtext:[25]:rawtext--> and/or virtual inheritance<!--rawtext:[25.11]:rawtext-->. However the C++ language does not impose that object layout so in principle a conversion could also happen even with non-virtual single inheritance.)

The point is simple: your C compiler will not know how to do that pointer conversion, so the conversion from Derived* to Base*, for example, must take place in code compiled with a C++ compiler, not in code compiled with a C compiler.

NOTE: you must be especially careful when converting both to void* since that conversion will not allow either the C or C++ compiler to do the proper pointer adjustments! The comparison (x == y) might be false even if (b == d) is true:

voidf(Base*b,Derived*d)
{
if(b==d){
ValidlycomparesaBase*toaDerived*
...
}

void*x=b;
void*y=d;
if(x==y){
BADFORM!DONOTDOTHIS!
...
}
}

As stated above, the above pointer conversions will typically happen with multiple and/or virtual inheritance, but please do not look at that as an exhaustive list of the only times when the pointer conversions will happen.

You have been warned.

If you really want to use void* pointers, here is the safe way to do it:

voidf(Base*b,Derived*d)
{
void*x=b;
void*y=static_cast<Base*>(d);
Ifconversionisneeded,itwillhappeninthestatic_cast<>
if(x==y){
ValidlycomparesaBase*toaDerived*
...
}
}

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.9] Can my C function directly access data in an object of a C++ class?

Sometimes.

(For basic info on passing C++ objects to/from C functions, read the previous FAQ).

You can safely access a C++ object's data from a C function if the C++ class:

If the C++ class has any base classes at all (or if any fully contained subobjects have base classes), accessing the data will technically be non-portable, since class layout under inheritance isn't imposed by the language. However in practice, all C++ compilers do it the same way: the base class object appears first (in left-to-right order in the event of multiple inheritance), and member objects follow.

Furthermore, if the class (or any base class) contains any virtual functions, almost all C++ compliers put a void* into the object either at the location of the first virtual function or at the very beginning of the object. Again, this is not required by the language, but it is the way "everyone" does it.

If the class has any virtual base classes, it is even more complicated and less portable. One common implementation technique is for objects to contain an object of the virtual base class (V) last (regardless of where V shows up as a virtual base class in the inheritance hierarchy). The rest of the object's parts appear in the normal order. Every derived class that has V as a virtual base class actually has a pointer to the V part of the final object.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


[32.10] Why do I feel like I'm "further from the machine" in C++ as opposed to C?

Because you are.

As an OO programming language, C++ allows you to model the problem domain itself, which allows you to program in the language of the problem domain rather than in the language of the solution domain.

One of C's great strengths is the fact that it has "no hidden mechanism": what you see is what you get. You can read a C program and "see" every clock cycle. This is not the case in C++; old line C programmers (such as many of us once were) are often ambivalent (can you say, "hostile"?) about this feature. However after they've made the transition to OO thinking, they often realize that although C++ hides some mechanism from the programmer, it also provides a level of abstraction and economy of expression which lowers maintenance costs without destroying run-time performance.

Naturally you can write bad code in any language; C++ doesn't guarantee any particular level of quality, reusability, abstraction, or any other measure of "goodness."

C++ doesn't try to make it impossible for bad programmers to write bad programs; it enables reasonable developers to create superior software.

[Top |Bottom |Previoussection |Nextsection |SearchtheFAQ ]


E-mail the author
[C++ FAQ |Tableofcontents |Subjectindex |Abouttheauthor |© |Downloadyourowncopy]
Revised Aug 26, 2010

<think>好的,用户想了解C语言C++文件的区别,特别是.c.cpp扩展名的区别以及它们分别用于哪种编程语言。首先,我需要明确这两种文件扩展名对应的编程语言。C语言使用.c,C++使用.cpp,这是基础。 接下来,用户可能想知道历史背景。比如为什么会有这两种不同的扩展名,是否有其他扩展名存在过。根据引用[1][2],.cpp的由来是因为C++的plus plus,而WindowsDOS系统更偏向使用.cpp,而Linux/Unix可能用.cc更多。这里需要解释不同操作系统的偏好,可能还有macOS的情况,如Xcode首选.cpp,这也需要提到。 然后,用户可能关心实际使用中的区别。比如编译器如何处理这两种文件,是否会影响编译方式。例如,gccg++在编译时会根据扩展名选择不同的编译器,C++文件需要链接标准库,而C文件则不会。这部分需要详细说明,因为这对用户编写编译代码有实际影响。 另外,用户可能想知道混合使用的情况,比如在C++项目中调用C代码,这时候需要extern "C"来避免名称修饰的问题。这也是一个常见的应用场景,应该提到。 还有,用户可能对文件扩展名的统一性有疑问,为什么有些项目用.cpp,有些用.cc,这里可以结合引用中的内容,提到市场占有率统一性的问题,如Windows的高占有率使得.cpp更普遍。 最后,需要总结两者的主要区别,包括用途、编译器处理、应用场景等,确保用户有一个清晰的对比。同时,生成的相关问题要覆盖扩展名选择、混合编程、历史原因以及跨平台差异,这样用户如果有进一步的问题,可以参考这些方向。</think>### C语言与C++文件扩展名的区别 #### 1. **基础定义** - **.c文件**:是C语言源代码文件的标准扩展名,用于存储纯C语言编写的代码。例如: ```c #include <stdio.h> int main() { printf("Hello, C!"); return 0; } ``` - **.cpp文件**:是C++源代码文件的标准扩展名,用于存储包含C++特性(如类、模板、异常处理)的代码。例如: ```cpp #include <iostream> int main() { std::cout << "Hello, C++!"; return 0; } ``` #### 2. **历史与平台差异** - **起源**: - `.cpp`扩展名源于“C plus plus”的缩写,直观表示C++代码[^2]。 - `.cc`扩展名在Linux/Unix系统中更常见,但Windows环境下普遍使用`.cpp`[^1]。 - **编译器行为**: - 使用`gcc`编译`.c`文件时,默认按C语言标准处理;编译`.cpp`文件时,会调用`g++`并按C++标准处理。 - C++文件编译时自动链接标准库(如`libstdc++`),而C文件不会。 #### 3. **语法与功能差异** - **C语言限制**: - 不支持面向对象特性(类、继承)。 - 无命名空间、模板或异常处理。 - **C++增强**: - 支持面向对象编程泛型编程。 - 引入标准模板库(STL)、运算符重载等。 #### 4. **混合编程场景** - 在C++中调用C代码时,需用`extern "C"`声明以避免名称修饰(name mangling)问题: ```cpp extern "C" { #include "c_library.h" } ``` #### 5. **实际应用建议** - **扩展名选择**: - 纯C项目使用`.c`,C++项目使用`.cpp`。 - 跨平台项目建议统一用`.cpp`以兼容Windows环境[^2]。 - **编译命令**: - C语言:`gcc main.c -o prog` - C++:`g++ main.cpp -o prog`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值