为什么在main()之前声明会导致语法错误“数字常量之前的错误:“ error:Expected')'?

时间:2018-08-12 17:55:34

标签: c++ c debugging assert

为什么在main()调用之前使用assert会导致编译错误?它将导致编译错误(语法错误):

  

test.cpp:4:8:错误:数值常量前应有')'

注意:我试图理解为什么在main外部调用它时出现语法错误。 这与“数字常量”之类的东西有关,但与函数/宏称为外部主函数不一样。如果错误更简单,如函数/宏称为外部主函数,那么我的问题就不会有任何道理。

#include <stdio.h>
#include <assert.h>

assert(0); //If I comment assert from here, then it compiles fine.

int main()
{
  assert(0);
  return 0;
}

4 个答案:

答案 0 :(得分:3)

由于所有其他答案都是“因为您无法执行此操作而没有用”,因此下面将深入探讨错误消息的外观。

简短的原因是编译器不聪明,而且他们也不是优秀的老师。

当我们,经验丰富的人类程序员,请看下面的代码

assert(0);
int main(void){}

我们认为第一行是调用函数的尝试,并以此作为解释为什么无效和应该写什么的起点。在识别您的意图时,需要花一些心思,因为您用错误的代码表达了该意图。

编译器无法理解您的想法,根据定义,它唯一可以识别您意图的方法是代码是否有效。由于它不了解您要执行的操作,因此无法提供有用的建议。

编译器实际上所做的只是一次输入您的代码,一次获取一个令牌,然后根据语法对其进行解析。如果代码不合语法,那么下一个标记将与任何语法规则都不匹配。然后,编译器会告诉您什么是有害令牌。在这种情况下,令人讨厌的令牌是数字常量0

0之前的标记被毫无争议地解析,但这并不意味着它们将按照您的意图进行解释。

很难完全分析这种特定情况,因为<assert.h>声明assert为宏,而且我不知道它在您的系统中扩展了什么。为了使说明更容易一点,让我们使用普通函数:

/* sample program 1 */
foo(0);
int main(void){}

以上代码无法编译。我的编译器说

error: expected declaration specifiers or '...' before numeric constant

但是此版本略有更改:

/* sample program 2 */
foo();
int main(void){}

只编译一些警告,因为在旧式C中,第一行是函数foo的有效声明,使用隐式int返回类型!如果我打算以某种方式“在main之前调用foo,那完全是失败的。如果我只打算声明foo,那么我只是使用过时的语言功能而感到内.。

现在,了解了第二个示例之后,请回顾一下第一个示例。当编译器读取前两个标记foo(时,一切都很好。该程序仍然符合(老式)C的语法。然后到达0,无法继续。因此,它告诉我数字常数就是问题所在。

现在,它说“正在期待”的那些事情呢?这些是有效程序中接下来可以使用的令牌。它建议使用声明说明符列表,而不要使用立即),因为这也是有效的:

foo(int);
int main(){}

即使使用旧式的函数定义,也可能是这样的延续:

foo(i)
  int i;
{
}
int main(){}

最底线:每当出现解析错误时,编译器都会报告您的程序从所有可能的有效程序集中语法上偏离的点。解析与您的意图发生明显差异的时间有时更早。有时要早很多。在这种情况下,编译器的“预期”令牌可能是完全不相关的。

答案 1 :(得分:0)

您无法调用自由函数(它是assert(通常是宏,但最终仍是在全局范围内运行的代码之类的函数)或任何其他函数其他函数)(不过您可以 调用函数,作为初始化全局变量(在C ++中)的一部分)。那就是为什么。

assert移至main或其他功能中。

答案 2 :(得分:0)

在C语言中,代码只能在函数内部执行。因此,如果将任何代码放置在函数之外,则会出现编译错误。

在对象创建期间调用构造函数时,C ++允许使用非常量初始化全局变量。

答案 3 :(得分:0)

main是程序的入口点。在main之前运行的唯一代码是初始化代码。如果要让断言在main之前运行,则可以在其构造函数中有一个带有断言的全局类,例如:

class assert_class {
  assert_class() { assert(0); }
};
assert_class assert_here;

int main()