Why having assert before main() causing syntax error "error: expected ')' before numeric constant"?

Why having assert before main() causing syntax error "error: expected ')' before numeric constant"?

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

test.cpp:4:8: error: expected ')' before numeric constant

注意:我试图理解为什么在 main 之外调用它会出现语法错误。 这与 "numeric constant" 之类的东西也有关,但与调用 side main 函数的函数/宏无关。 如果错误更简单,例如调用 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;
}

您不能调用自由函数(无论是 assert(通常是一个宏,但最终仍然是全局范围 运行 中的代码 ,例如 一个函数)或任何其他函数)来自全局范围(你 可以 但是调用函数作为初始化全局变量的一部分(在 C++ 中))。这就是为什么。

assert 移动到 main 或其他函数中。

在C语言中,代码只能在函数内部执行。因此,如果您将任何代码放在函数之外,您将得到编译错误。

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

main 是程序的入口点。 main 之前的唯一代码 运行 是初始化代码。如果你想在 main 之前使用 assert 运行,你可以在其构造函数中使用全局 class 和 assert,例如:

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

int main() 

由于所有其他答案都是 "it didn't work because you can't do that",这里有一个深入探讨为什么错误消息看起来像这样。

简短的原因是编译器不聪明,他们也不是好老师。

当我们这些经验丰富的人类程序员看到这段代码时

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 return 类型!如果我的意图是以某种方式 "call foo before main" 那么它完全失败了。如果我的意图只是声明 foo 那么我只是因为使用了过时的语言功能而感到内疚。

现在,了解了第二个样本,再回头看看第一个样本。当编译器读取前 2 个标记 foo( 时,一切正常。该程序仍然符合(老式的)C 的语法。然后它到达 0 并且无法继续。所以它告诉我数字常数是问题所在。

那么它说的那些东西呢 "expecting"?这些是有效程序中接下来可以出现的标记。它建议声明说明符列表而不是直接 ),因为这也是有效的:

foo(int);
int main(){}

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

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

底线:每当出现解析错误时,编译器都会报告您的程序在语法上从所有可能的有效程序集中 偏离的点。解析与您的意图 语义 偏离的点有时会更早。有时会早很多。在那种情况下,编译器的 "expected" 标记可能完全无关紧要。