这个题目问C和C++之间的区别是什么,导致这段代码在后者无法编译?

7

我刚刚在想关于问题 'Hello, World!' in C without semicolons and without 'if', 'while', or 'for' statements 的内容。

以下代码能在C中运行,但不能在C++中:

int main(int argc, char *argv[printf("Hello, World!\n")]) {}

在C++中,我遇到了这个错误:
error: expected ‘,’ or ‘...’ before ‘argv’|
warning: second argument of ‘int main(int, char*)’ should be ‘char **’ [-Wmain]|
||=== Build finished: 1 errors, 1 warnings ===|

为什么在C++中它不起作用?


@CarlNorum:那不是问题的关键。事实上,OP试图将其赋给char **(至少一次数组衰减),但解析错误意味着编译器正在误解。 - Lightness Races in Orbit
没错,现在我再看它时就是这样。为可变长度数组欢呼!=) - Carl Norum
你的编译器版本是多少?你确定你正确地复制了代码吗?我完全无法复现这个问题。 - Lightness Races in Orbit
@Lightness Races in Orbit:是的,我已经正确复制了代码。我正在使用codblocks IDE 10.05。当我在Ubuntu终端上运行gcc -v时,我得到了版本:gcc版本4.6.1(Ubuntu/Linaro 4.6.1-9ubuntu3)。 - Forever Learner
@LightnessRacesinOrbit:在GCC中,它在C中运行,但在C++中不起作用 - Mike Seymour
显示剩余2条评论
3个回答

19
因为C++没有任何可变长度数组功能。
在以下参数中,argv是一个可变长度数组: char *argv[printf("Hello, World!\n")] 指定数组大小的表达式为:
printf("Hello, World!\n")

这个表达式的结果是int类型,表示传输的字符数(如果出现错误则为负数)。
[]中的表达式不是常量的数组,例如printf表达式中的示例,是一个可变长度数组。这些数组也允许用作函数参数的类型。
可变长度数组是C语言中C99引入的一项特性,而C ++没有引入这个特性。

5
你能详细说明一下你的回答吗?对于评分为七分来说,它还相当不完整。 - Lightness Races in Orbit
@LightnessRacesinOrbit 好的,我正在做。 - ouah
C语言有变量数组特性吗?这实际上在C中编译是个奇迹,我认为这不是标准。 - ugoren
@ugoren:C99可以,C89/C90不行。GCC在C++中支持它们作为扩展;无论是否允许编译此奇怪的代码我无法说。无论如何,我倾向于认为这是C的可变长度数组的一个漏洞,或者是GCC实现的一个漏洞,但我无法确定。 - Lightness Races in Orbit

8
正如错误信息所示,main 函数期望其第二个参数是 char** 类型。然而,由于数组衰减规则,以下两种方式都是可行的:
int main(int argc, char** argv);   // OK
int main(int argc, char* argv[]);  // OK

事实上,以下内容也是等效的,因为数组衰减不关心维度:
int main(int argc, char* argv[5]); // OK

然而,在C99中,数组可以具有可变长度,但在C++中不是这种情况。因此,对于该数组维度使用非常量表达式(在您的情况下为printf(“Hello world \n”))是无效的语法。
int main(int argc, char* argv[printf("Hello, world!\n")]); // Not OK!

这个无效的语法会让解析器混淆,并在编译器中产生误导性错误。
如果你稍微简化代码,去掉函数调用表达式(但仍然使用非常量作为数组边界),那么你将得到一个更相关的错误信息
int x = 5;
int main(int argc, char* argv[x]) {}
// error: array bound is not an integer constant

实际上,GCC 4.1.2 对您的原始代码也会给出这个有用的提示信息, 因此您的编译器一定非常老旧...或者您的测试用例有问题尽管更新得多的GCC 4.5.1也会产生您发布的提示信息

@Keith:谢谢,我想那样做更好。不过这样一来我最新的修改都没了! - Lightness Races in Orbit
1
“数组衰减规则”通常指将数组表达式衰减/转换为指向其第一个元素的指针([C99](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)6.3.2.1p3)。这是一条独特的规则,适用于参数声明,由标准描述为调整而非转换(C99 6.7.5.3p7)。 - Keith Thompson
两种标准都没有使用“decay”这个词,但我经常看到它用于指代隐式数组到指针转换;例如,参见comp.lang.c FAQ的问题6.3。N3290(我所拥有的最接近C++11标准的东西)4.2 [conv.array]说这种转换可以发生;5p8 [expr]说当它被隐式执行时。参数调整规则在8.3.5p5 [dcl.fct]中。 - Keith Thompson
@Keith:那我想我创造了一个非规范性的术语 :) - Lightness Races in Orbit
有时牙医也会使用它,所以这是有先例的。 - Lightness Races in Orbit
显示剩余3条评论

3
在C语言中,char *argv[some_expression]是一个变长数组,因此当用作函数参数时被解释为指针(就像在声明函数参数时使用固定长度或未知长度的数组一样)。
在C++中,不存在变长数组,因此这是无效的。 char * argv[some_constant]char * argv[] 都是有效的,并且等同于char ** argv - 但是显然这些都不会产生副作用,因此不能用来解决那个愚蠢的练习。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接