因为导师最近给发了一个c语言和c++混编的程序,打开出现了很多错误,但本人对c语言的语法不太熟悉,所以在老师帮忙下(将c语言转成c++)调通后,自己又调了一遍,总结了一下改的东西
1.首先在c++中定义c语言函数的话,因为C++ 编译器会对函数名进行修饰(添加参数类型信息),而 C 编译器不会。所以需要
使用 extern "C"
告诉 C++ 编译器:
“此函数/变量需按 C 语言的规则生成符号,不要进行名称修饰”。具体语法如下:
#ifdef __cplusplus
extern "C" { // 告诉 C++ 编译器以下函数按 C 规则链接
#endif
void c_print(const char* msg); // 声明 C 函数
#ifdef __cplusplus
}
#endif
因为我现在要将c语言转成c++,所以直接将带有这一部分的代码注释掉,再将里面的函数声明改成c++的形式即可。
2.c语言在使用复数类型的变量时,C++内置了std::complex
模板类,而C语言在C99标准中引入了复数支持,但两者的语法和用法有所不同。在C++中是std::complex<double>
,而C语言中则是double complex
类型。所以需要注意以下几点
头文件和命名空间:
- C++需要包含
<complex>
头文件,并且使用std::complex
,可能需要命名空间。 - C语言需要包含
<complex.h>
,并且使用double complex
类型,函数名可能带有下划线,比如creal
和cimag
。
类型声明和初始化:
- C++中使用
std::complex<double> z(1.0, 2.0);
来初始化。 - C语言中使用
double complex z = 1.0 + 2.0 * I;
,其中I
是虚数单位。
访问实部和虚部:
- C++中使用
real(z)
和imag(z)
成员函数,或者std::real(z)
和std::imag(z)
。 - C语言中使用
creal(z)
和cimag(z)
函数。
数学运算和函数:
- C++可以使用运算符重载,如
+
,-
,*
,/
等直接操作复数。 - C语言需要使用复数特定的函数,如
conj
、cexp
等,这些函数可能需要包含特定头文件。
兼容性和标准差异:
- C++的
std::complex
支持更多的运算符和运算,而C语言的复数函数较为基础。 - C++11之后支持
constexpr
和更高级的特性,而C语言的复数功能较为有限。
具体语法如下
cpp
// C++
#include <complex>
std::complex<double> z(1.0, 2.0);
double real_part = std::real(z);
c
// C
#include <complex.h>
double complex z = 1.0 + 2.0 * I;
double real_part = creal(z);
3.代码中有以下两行代码
# define Inf numeric_limits<double>::infinity()
# define NaN numeric_limits<double>::quiet_NaN()
在后面使用到Inf时一直报错,然后将其改成就能正常运行了
const double Inf = numeric_limits<double>::infinity();
const double NaN = numeric_limits<double>::quiet_NaN();
主要原因在于:
#define
和 const
的区别
-
#define
是一个预处理指令,它会在编译之前进行宏替换。宏并不会像常规的变量那样进行类型检查或者作用域检查。也就是说,它会直接用给定的表达式替换代码中的每个Inf
和NaN
,没有类型安全和作用域限制。它是一种简单的文本替换。 -
const
则是声明一个常量,编译器会进行类型检查,并且会在编译时为该常量分配内存地址。const
常量是类型安全的,并且具有作用域。
为什么 #define
可能会导致错误
#define Inf numeric_limits<double>::infinity()
这样做会让预处理器在代码中每次看到 Inf
时都将其替换成 numeric_limits<double>::infinity()
,而这可能会导致一些问题。具体原因如下:
-
类型不匹配或作用域问题:
numeric_limits<double>::infinity()
返回的是一个double
类型的常量,但是#define
并不关心这个常量的类型,它只是简单的做文本替换。当你在代码中使用Inf
时,编译器无法知道它是一个double
类型的常量,有时可能会因为上下文的不同导致类型不匹配的错误,尤其是当你在不期望的地方使用Inf
时(比如在不需要double
类型的地方)。 -
代码可读性和调试问题:宏替换并不会产生变量,它不会在调试时显示出变量的名字和类型,给代码的可维护性带来困难,特别是当错误信息中没有明确的标识符时。
为什么 const double
不会报错
当你使用 const double Inf = std::numeric_limits<double>::infinity();
时,Inf
被声明为一个具有明确类型 (double
) 的常量。编译器会根据 std::numeric_limits<double>::infinity()
的返回值的类型(double
)来进行类型检查,并且保证常量 Inf
在整个作用域内有效。const
常量不会引起宏替换的问题,它会保留类型信息,且具有作用域限制,这样可以避免类型冲突和其他潜在的错误。
4.因为我的代码中还包含
# define FADDEEVA(name) Faddeeva::name
# define FADDEEVA_RE(name) Faddeeva::name
意思是
- 这个宏将
FADDEEVA(name)
替换为Faddeeva::name
。 - 它将
Faddeeva::name
中的name
替换为具体的函数或变量名。Faddeeva
可能是一个命名空间或者是一个类名,name
代表具体的函数或类成员。这个宏的作用是简化代码,直接通过FADDEEVA(name)
来访问Faddeeva
命名空间或类中的内容。
所以在将c语言改成c++时,如果这部分函数是使用c语言进行声明的,需要将其改成c++的命名空间或者相应的类。