哪里C不是C++的子集?

n00*_*ki3 111 c c++

我在很多书中读到C是C++的一个子集.

有些书说C是C++的一个子集,除了细节之外.

代码在C中编译但在C++中编译的情况有哪些?

Joh*_*itb 133

如果你比较C89C++那么这里有几件事情

在C++中没有暂定的定义

int n;
int n; // ill-formed: n already defined
Run Code Online (Sandbox Code Playgroud)

int []和int [N]不兼容(C++中没有兼容的类型)

int a[1];
int (*ap)[] = &a; // ill-formed: a does not have type int[]
Run Code Online (Sandbox Code Playgroud)

没有K&R功能定义样式

int b(a) int a; { } // ill-formed: grammar error
Run Code Online (Sandbox Code Playgroud)

嵌套结构在C++中具有类范围

struct A { struct B { int a; } b; int c; };
struct B b; // ill-formed: b has incomplete type (*not* A::B)
Run Code Online (Sandbox Code Playgroud)

没有默认的int

auto a; // ill-formed: type-specifier missing
Run Code Online (Sandbox Code Playgroud)

C99增加了很多其他案例

参数的数组维度中没有特殊的声明说明符处理

// ill-formed: invalid syntax
void f(int p[static 100]) { }
Run Code Online (Sandbox Code Playgroud)

没有可变长度数组

// ill-formed: n is not a constant expression
int n = 1;
int an[n];
Run Code Online (Sandbox Code Playgroud)

没有灵活的阵列成员

// ill-formed: fam has incomplete type
struct A { int a; int fam[]; }; 
Run Code Online (Sandbox Code Playgroud)

没有限制限定符来帮助别名分析

// ill-formed: two names for one parameter?
void copy(int *restrict src, int *restrict dst);
Run Code Online (Sandbox Code Playgroud)

  • 还有另一个(无用的)C89到C++:`typedef;`是C中的合法TU,但不是C++中的. (3认同)
  • @FUZxxl真的吗?什么是推断类型的'a`? (3认同)
  • @FUZxxl啊谢谢.因此`auto x;`在最新版本中无效,但例如`auto x = 0;`是.我有点震惊:) (3认同)

Nav*_*een 48

在C中,sizeof('a')等于sizeof(int).

在C++中,sizeof('a')等于sizeof(char).

  • 这可以简化为:在C中​​,''a'`是一个`int`.在C++中,`'a'`是一个`char`. (43认同)
  • 这是我最喜欢的C主义. (2认同)

Gra*_*row 36

C++也有新的关键字.以下是有效的C代码,但不会在C++下编译:

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;
Run Code Online (Sandbox Code Playgroud)

  • 不,如果C是C++的严格子集,那么每个C程序都是有效的C++程序,但事实并非如此.问题是为什么它不是真的,这就是原因的一个例子. (21认同)
  • @yeyeyerman:不.因为它是一个子集,所有C代码也必须是有效的C++.此示例中的代码是有效的C而不是C++. (18认同)

Meh*_*ari 20

有很多东西.只是一个简单的例子(它应该足以证明C不是C++的适当子集):

int* test = malloc(100 * sizeof(int));
Run Code Online (Sandbox Code Playgroud)

应该用C编译而不是用C++编译.

  • @Imagist:我经常听到C程序员的反面.他们认为添加演员阵容的风格很差,因为它可能会隐藏错误.好的C代码*不*使用演员表. (16认同)
  • 答案很长:malloc返回`void*`,它在C中可以分配给任何指针类型,并且C++不能分配给任何其他指针类型. (7认同)
  • 这是合法的C.演员阵容是不必要的,可能出错,并且掩盖了未能包括<stdlib.h>.我认为Mehrdad的陈述是用C语写的正确方法. (7认同)
  • 想象一下:ANSI C89标准定义的C编译器不应该抱怨. (5认同)
  • C++应该要求显式转换为`int*`. (3认同)
  • @jalf:我认为使用隐式函数声明是不好的样式,我强烈建议总是使用-Wall -Werror(GCC)进行编译.这可以防止这里的强制转换掩盖无法包含<stdlib.h>的情况.如果有任何机会将代码编译为C++,那么最好进行强制转换. (2认同)

Pav*_*aev 16

在C++中,如果声明一个struct,unionenum,它的名称可以立即访问,而不需要任何限定符:

struct foo { ... };
foo x; // declare variable
Run Code Online (Sandbox Code Playgroud)

在C中,这将不起作用,因为这样声明的类型存在于它们自己的不同命名空间中.因此,你必须写:

struct foo { ... };
struct foo x; // declare variable
Run Code Online (Sandbox Code Playgroud)

注意struct第二行是否存在.你必须为(unionenum使用他们各自的关键字)做同样的事情,或使用typedef技巧:

typedef struct { ... } foo;
foo x; // declare variable
Run Code Online (Sandbox Code Playgroud)

因此,您可以在C中将几种类型的不同类型命名为相同,因为您可以消除歧义:

struct foo { ... };
typedef enum { ... } foo;

struct foo x;
foo y;
Run Code Online (Sandbox Code Playgroud)

但是,在C++中,虽然您可以在引用时struct使用关键字为名称添加前缀,但是struct命名空间会合并,因此上面的C片段无效.另一方面,C++特别提出异常,允许该类型的类型和typedef具有相同的名称(显然没有效果),允许使用typedefC中未更改的技巧.


Dav*_*ley 8

这还取决于您使用的C种类.Stroustrup使得C++尽可能兼容,并且与1989 ANSI和1990 ISO标准不相容,而且1995版没有改变.C委员会与1999标准的方向略有不同,C++委员会已经改变了下一个C++标准(可能在明年左右),以符合一些变化.

Stroustrup列出了"C++编程语言"特别版附录B.2中与C90/C95的不兼容性(第3版附带了一些附加材料):

'a'是一个intC,一个char在C++中.

枚举的大小int在C中,不一定在C++中.

C++ //对行尾有注释,C没有(虽然它是常见的扩展).

在C++中,struct foo {定义放入foo全局命名空间,而在C中则必须将其称为struct foo.这允许struct定义在外部作用域中隐藏名称,并具有一些其他后果.此外,C允许更大的struct定义范围,并允许它们返回类型和参数类型声明.

一般来说,C++对类型更加苛刻.它不允许将整数分配给an enum,并且void *在没有强制转换的情况下不能将对象分配给其他指针类型.在C中,可以提供一个过大的初始值设定项(char name[5] = "David"其中C将丢弃尾随的空字符).

C89允许int在许多上下文中隐含,而C++则不允许.这意味着所有函数都必须在C++中声明,而在C89中,通常可以假设int函数声明中适用的所有内容.

在C中,可以使用带标签的语句从块外部跳转到内部.在C++中,如果它跳过初始化,则不允许这样做.

C在外部联系方面更加自由.在C中,一个全局const变量是隐式的extern,而在C++中则不然.C允许在没有a的情况下多次声明全局数据对象extern,但在C++中则不然.

许多C++关键字不是C中的关键字,或者是#define标准C头中的关键字.

还有一些C的旧功能不再被认为是好的风格.在C中,您可以在参数列表后面声明一个带有参数定义的函数.在C中,像一个声明int foo()该装置foo()可以采取任何数量的任何类型的参数,而在C++中它相当于int foo(void).

这似乎涵盖了Stroustrup的所有内容.

  • 但是,这是C++无法做到的事情.我想我们正在研究你可以用C而不是C++做的事情. (4认同)
  • @RobH:这对C89来说都是如此,但对于C99则不然. (2认同)

Pau*_*gar 6

如果您使用 gcc,您可以使用警告-Wc++-compat向您发出有关 C 代码的警告,这些代码在 C++ 中以某种方式是可疑的。它目前在 gcc 本身中使用,并且最近变得更好(也许尝试每晚版本以获得最佳效果)。

(这并不能严格回答问题,但人们可能会喜欢它)。


Sin*_*nür 5

#include <stdio.h>

int new (int n) {
    return n/2;
}

int main(void) {
    printf("%d\n", new(10));
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

另请参阅C++ 常见问题解答条目


Dan*_*ker 5

我认为最大的区别是这是一个有效的 C 源文件:

int main()
{
    foo();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有foo在任何地方声明。

除了语言差异之外,C++ 还对其从 C 继承的库进行了一些更改,例如,某些函数返回const char *而不是char *.

  • @jalf C99 草案记录了对 C89 的更改,并包括“删除隐式 int”和“删除隐式函数声明”。 (2认同)