C在哪里不是C ++的子集?[关闭]


116

我读过很多书,其中C是C ++的子集。

有些书说C是C ++的子集,除了一些小细节

在什么情况下代码将用C而不是C ++进行编译,在什么情况下?

Answers:


135

如果您与进行比较C89C++那么以下几点

C ++中没有暂定定义

int n;
int n; // ill-formed: n already defined

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

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

没有K&R函数定义样式

int b(a) int a; { } // ill-formed: grammar error

嵌套结构在C ++中具有类作用域

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

没有默认的int

auto a; // ill-formed: type-specifier missing

C99增加了很多其他情况

对参数的数组维中的声明说明符无特殊处理

// ill-formed: invalid syntax
void f(int p[static 100]) { }

没有可变长度的数组

// ill-formed: n is not a constant expression
int n = 1;
int an[n];

没有灵活的数组成员

// ill-formed: fam has incomplete type
struct A { int a; int fam[]; }; 

无限制限定符,有助于别名分析

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

@mehrdad,谢谢。oO在用C声明嵌套结构时不知道必须创建一个变量。已修复。
Johannes Schaub-litb

3
从C89到C ++还有另一种(无用的)C89:typedef;在C中是合法的TU,但在C ++中不是。
Flexo

请注意,这auto a;在最新的C ++标准修订版中有效。
FUZ

3
@FUZxxl真的吗?推导的类型是a什么?
Johannes Schaub-litb 2015年

3
@FUZxxl啊,谢谢。因此auto x;在最新版本中无效,但例如auto x = 0;。起初我有些震惊:)
Johannes Schaub-litb

50

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

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


46
可以简化为:在C中​​,'a'int。在C ++中,'a'是一个char
pmg 2010年

38

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

int class = 1;
int private = 2;
int public = 3;
int virtual = 4;

1
是的,但这正是子集的含义。
yeyeyerman

20
@yeyeyerman:不。要成为子集,所有C代码也必须是有效的C ++。此示例中的代码是有效的C,但不是C ++。
jalf

24
不,如果C是C ++的严格子集,则每个C程序都是有效的C ++程序,但这不是事实。问题是为什么它不是真的,这是为什么的一个例子。
Graeme Perrow,2009年

哈!没想到这个!
加布·罗耶

20

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

int* test = malloc(100 * sizeof(int));

应该在C中编译,但不能在C ++中编译。


3
C ++应该要求显式转换为int*
Mehrdad Afshari 2009年

8
长答案:malloc返回void *,它可以在C中分配给任何指针类型,而C ++不能分配给任何其他指针类型。
丹尼尔·艾威克

5
想象中:ANSI C89标准定义的C编译器不应抱怨。
Mehrdad Afshari,2009年

7
这是合法的C。强制转换是不必要的,可能会出错,并且掩盖了无法包含<stdlib.h>的情况。我认为迈赫达德的说法是将它写在C正确的方式
大卫·索恩利

16
@Imagist:我通常会听到C程序员的反对意见。他们认为添加演员表的风格很差,因为它可能会掩盖错误。良好的C代码也没有使用演员。
jalf

16

在C ++中,如果你声明structunion或者enum,它的名字是不带任何修饰词立即访问:

struct foo { ... };
foo x; // declare variable

在C语言中,这是行不通的,因为这样声明的类型存在于各自不同的命名空间中。因此,您必须编写:

struct foo { ... };
struct foo x; // declare variable

注意struct第二行上的存在。你要为做同样的unionenum(使用各自的关键字),或使用typedef技巧:

typedef struct { ... } foo;
foo x; // declare variable

因此,由于可以消除歧义,因此可以在C中使用几种不同类型的名称相同的名称。

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

struct foo x;
foo y;

但是,在C ++中,尽管您可以在引用struct名称时使用关键字作为前缀struct,但名称空间会合并,因此上述C代码段无效。另一方面,C ++专门为允许类型和该类型的类型定义具有相同的名称(显然无效)而允许使用typedefC不变的技巧。


1
你的最后一个例子是无效的C:这三个标签(structunionenum)共享相同的命名空间。一个更好的例子是struct foo { ... }; typedef enum { ... } foo;
拍摄

@schot:您当然是对的,谢谢您的纠正。更新。
帕维尔·米纳夫

8

这也取决于您使用的是哪种C。Stroustrup使C ++尽可能兼容,但不再兼容1989年的ANSI和1990年的ISO标准,而1995年的版本则保持不变。C委员会的方向与1999年标准有所不同,C ++委员会已更改了下一个C ++标准(可能在明年左右发布),以适应某些更改。

Stroustrup在“ C ++编程语言”特别版(这是第3版,其中添加了一些补充材料)的附录B.2中列出了与C90 / C95不兼容的内容:

'a'int在C中是C,char在C ++中是a 。

枚举的大小int用C表示,不一定用C ++表示。

C ++ //在行尾添加了注释,而C没有(尽管这是一个常见的扩展)。

在C ++中,将struct foo {定义放入foo全局名称空间,而在C中,则必须将其称为struct foo。这样一来,struct定义就可以在外部范围内隐藏名称,并带来其他一些后果。同样,C允许更大的struct定义范围,并允许它们在返回类型和参数类型声明中使用。

一般而言,C ++对类型很挑剔。不允许将整数分配给enum,并且void *如果没有强制转换,则不能将对象分配给其他指针类型。在C中,可以提供一个超大的初始化程序(char name[5] = "David"其中C将丢弃尾随的空字符)。

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

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

C在外部联系方面更为自由。在C中,全局const变量是隐式的extern,而在C ++中则不是。C允许多次声明全局数据对象而没有使用extern,但是在C ++中不是这样。

许多C ++关键字不是C中的关键字,也不是#define标准C标头中的d。

还有一些C的较旧的功能,它们不再被认为是好的样式。在C语言中,可以在参数列表之后声明带有参数定义的函数。在C中,像这样的声明int foo()意味着foo()可以接受任意数量的任何类型的参数,而在C ++中,它等效于int foo(void)

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


我们不要忘记这样一个事实,在C中,必须在作用域的开头(即紧接在大括号之后)声明变量,而C ++允许在任何地方声明变量。
罗布

4
但是,这是C ++可以做到的,而C无法做到。我认为我们正在研究可以用C而不是C ++进行的操作。
David Thornley 2009年

2
@RobH:C89确实如此,但C99却不是。
jamesdlin

6

如果使用gcc,则可以使用警告-Wc++-compat向您发出有关C代码的警告,而C代码在C ++中是可疑的。它目前在gcc本身中使​​用,并且最近得到了更好的改进(也许可以尝试每晚使用以获得最佳性能)。

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


1
我以为我永远不会投票赞成一个没有答案的问题
eharo2 '19

4

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

int main()
{
    foo();
}

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

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


是的,在C语言中不需要原型,但是通常不使用它们被认为是不好的做法。
罗伯特·甘布尔

1
您应该s,C,C89,注意,这是无效的C99源文件。
Johannes Schaub-litb

它是无效的还是只是在C99中弃用?
jalf

2
@jalf C99草案记录了对C89的更改,并且包括“删除隐式int”和“删除隐式函数声明”。
Johannes Schaub-litb



-2

C编译器通常允许C ++不允许这样做。C ++比C语言严格得多。通常,其中一些差异取决于编译器。例如,g ++允许Intel C ++编译器不提供某些功能。即使编写得很好的C代码也无法使用现代C ++编译器进行编译。


-2

您不能仅通过语法比较语言。如果这样做,也许您可​​以将C视为C ++的子集。我认为C ++是OO(而C不是)这一事实足以说明C和C ++是不同的语言。


2
错误。C ++ 不仅是 OO。您可能会想到C ++之类的东西,例如“ C ++ = C + OO +通用编程+奖励”。换句话说,“ C&C ++〜= C”,其中〜=表示几乎相等。
paercebal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.