【学习笔记】《C Premier Plus》之C和C++的区别


1.函数原型

1.1 如果在声明一个函数时使圆括号为空

在C语言中意味着前向原型声明。
在C++语言中意味着函数没有原型,或者说默认为无参函数原型。

// In C Language, try the code and note the result
int slice();

int main(const int argc, char *argv[])
{
    //...
    slice(20, 50);
    //...
}

int slice(int a, int b)
{
    //...
}

上述示例在C编译器中可以通过,编译器假定使用的是ANSI C标准以前的旧形式。
C++编译器将声明int slice();解释为int slice(void);,与下面的函数定义int slice(int a , int b)属于两个不同的函数,因为参数列表不同。所以如果以C++文件编译会报错,函数使用前未声明。

1.2 同名函数

C语言标准不允许声明多个函数名相同的函数。

C++语言标准允许声明函数名相同,但参数列表不相同的多个函数。

2.字符类型

C语言中,字符变量占一个字节的内存,字符常量被作为int类型看待,占用4个字节的内存。

// In C Language, try the code and note the result
char ch = 'A';
printf("sizeof(ch)=%u, sizeof(\'A\')=%u\n", sizeof(ch), sizeof('A')); // sizeof(ch)=1, sizeof('A')=4

在C++中,字符常量和字符变量都被作为char类型看待,占用一个字节内存。

// In C Language, try the code and note the result
int x = 'ABCD';
char ch = 'ABCD';
printf("%d,%d,%c,%c\n", x, 'ABCD', c, 'ABCD');

用macOS Monterey 12.1系统(cmake 3.22.1, GNU Make 3.81, Apple clang 13.0.0)得到的结果如下

1094861636,1094861636,D,D

这里的'ABCD'意味着一个四字节的int值,其中第一个字节存储字母A的字符编码,第二个字节存储字母B的字符编码,以此类推。注意'ABCD'是书写int值的一种方式,"ABCD"是一个字符串,对应于内存中五个字节的内存块的地址。

如果把'ABCD'看作一个int值,它就是一个四字节的整数值,如果把它看作char类型,程序就只使用最后一个字节。用%s格式说明符打印'ABCD'会得到一个'CoreDump'错误,因为1094861636是一个越界地址。

使用像'ABCD'这样的值是因为它提供了一种方式来单独设置int中的每个字节。但由于它依赖于特定的字符码,而每两位十六进制数对应于一个字节,所以更好的方法是对整数常量使用十六进制值。

3.指向void的指针

C语言和C++语言都允许将任意类型的指针符值给void *类型的指针。

C语言允许将void *类型的指针直接赋值给其他类型的指针而不用使用显式类型转换。
C++要求必须显式进行类型转换。
不过建议使用中还是最好都加上类型转换,提高兼容性和可读性。

4.const修饰符

在C中全局const具有外部链接,而在C++中它具有内部链接。也就是说C++中的定义const double PI = 3.14159;相当于C中的static const double PI = 3.14159;,前提是这两个定义都在所有函数体的外部。

C++规则的意图是使得在头文件中使用const更加简单。如果常量是内部链接的,每个包含头文件的文件都会得到该常量的一份拷贝。如果是外部链接的话就必须在其他使用文件中进行extern引用声明。

C++可以使用extern使一个const值具有外部链接,所以两种语言都可以创建具有内部链接的常量和具有外部链接的常量。关键在于默认使用哪种链接。

5.结构联合枚举类型

5.1 标记与变量名

在C语言中,结构或联合的标记可以与其他类型的变量名相同,因为用结构类型声明变量时需要加上struct关键字。

// In C Language, try the code and note the result
struct duo
{
    int a;
    int b;
};

struct duo m;      // 合法
float duo = 100.f; // 合法,float型的变量名

/*
struct duo duo;
float duo = 100.f; // 不合法,因为跟上一行中的变量名duo冲突
*/

而在C++中可以直接用结构或联合的标记作为类型名,不能与其他类型变量名相同。

// In C++ Language, try the code and note the result
struct duo
{
    int a;
    int b;
}

struct duo m; // 合法
duo n;  // 合法,可以使用标记直接作为类型名

5.2 嵌套使用

在C/C++语言的结构中可以嵌套声明另一个结构。在后续的代码中,C语言允许直接使用任何一个结构,即使是在一个结构中嵌套定义的。

struct box
{
    struct point
    {
        int x;
        int y;
    } upperleft;
    struct point lowerright;
};

struct box ad;
struct point dot; // 合法

而在C++中需要使用命名空间作为限定。

struct box
{
    struct point
    {
        int x;
        int y;
    } upperleft;
    struct point lowerright;
};

struct box ad;
// struct point dot; // 错误,C++不允许
box::point dot;   // 正确使用方法

5.3 枚举类型

在枚举的使用中,C++比C更严格。
使用enum变量唯一能做的就是为它赋一个enum常量,然后与其他值比较。
不经过显式类型转换,不能把int值赋给enum变量。
不能递增一个enum变量。
C++允许在声明一个枚举变量时不用关键字,并且一个变量和enum类型具有相同的名字会引起冲突。

enum sample {sage, thyme, salt, pepper};
enum sample season;

season = sage;           // 在C和C++中都合法
season = (enum sample)2; // 在C和C++中都合法
season = 1;              // C给出警告,C++编译错误
season++;                // 在C中可以,C++编译错误

sample season_var;       // C中声明enum变量要加关键字enum,在C++中合法

6.内联函数

C++中内联函数默认是内部链接的,如果一个内联函数在多个文件中出现,必须具有相同的定义,使用相同的语言符号。不允许在一个文件中的定义里使用int参量而在另一个文件中的定义里使用int32_t参量,即使用typedef int int32_t;新建别名也不行。

C语言允许使用typedef定义的相同的参量类型。同时C语言允许混合使用函数的内联和外部定义。

7.C99特性

尽管传统上C可以看做C++的子集,但C99标准添加了一些C++所没有的特性,根据实际语言的扩展,可能有下面所列项。

  • 指定初始化项目
  • 复合初始化项目
  • 受限指针
  • 变长数组
  • 伸缩性数组成员
  • 可移植整数类型(stdint.h和inttypes.h)
  • 通用字符名
  • 附加的数学库函数
  • 通过fenv.h访问符点数环境
  • 预定义标识符如__func__
  • 具有可变数目参数的宏

8.其他要点

8.1 布尔类型

C语言中布尔类型是_Boolbool/true/false是通过宏定义来实现的,需要包含头文件stdbool.h

C++中布尔类型是boolbool/true/false都是关键字。

8.2 复数类型

C具有内建的复数类型并通过complex.h头文件来支持它们。

C++通过在complex头文件中提供一个复数类来支持复数类型。这两种方式互不兼容,C更关心数值运算的需要和惯例。

8.3 宽字符支持

C语言中wchar_t类型是在一些头文件中进行定义的(stddef.h/stdlib.h/wchar.h/wctype.h)。C99通过wchar.h头文件提供相应的IO支持包。C99支持多字节字符及其与宽字符之间的转换。

C++中wchar_t是一种内建类型,是一个关键字。C++通过iostream头文件提供宽字符的I/O支持。C++不支持多字节字符及其与宽字符之间的转换。

8.4 可选拼写

C语言中可以使用and/or/not来代替 &&/||/!,需要包含头文件iso646.h,是通过宏定义来实现的。

C++中可以直接使用and/or/not来代替&&/||/!,它们都是关键字。

(全文完)


本文作者 :phillee
发表日期 :2022年01月21日
本文链接
版权声明 :自由转载-非商用-非衍生-保持署名(创意共享3.0许可协议/CC BY-NC-SA 3.0)。转载请注明出处!
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

感谢您的支持

¥ 打赏

微信支付