为什么这在C中合法?

sna*_*nap 16 c language-design

我正在为我的大学编写一个编译器/语言课程的玩具C编译器.

我试图在C中充实符号解析的语义,并提出了我尝试对常规编译器clang&gcc的测试用例.

void foo() { }
int main() { foo(5); } // foo has extraneous arguments
Run Code Online (Sandbox Code Playgroud)

大多数编译器似乎只是警告无关的论点.

问题:这背后的根本原因是什么?

对于我的符号表生成/解析阶段,我正在考虑一个函数是一个带有返回类型的符号,以及几个参数化的参数(基于语法),每个参数都有一个相应的类型.

谢谢.

pax*_*blo 32

原型中没有列出参数的函数被认为具有不确定的数字,而不是零.

如果你真的想要零参数,它应该是:

void foo (void);
Run Code Online (Sandbox Code Playgroud)

空列表变体是古代C的延续,甚至在ANSI获得它之前,你有这样的东西:

add_one(val)
int val;
{
    return val + 1;
}
Run Code Online (Sandbox Code Playgroud)

(int作为声明符外部指定的默认返回类型和参数类型).

如果你正在做一个玩具编译器并且你并不担心每一小块C99的符合性,我只是抛出那个选项并需要某种参数列表.

它会让你的生活变得更加轻松,我怀疑人们是否需要使用这个"功能".

  • +1 - 旁注,这在C++中是*NOT*true. (7认同)
  • @paxdiablo:好的.我记得,因为每隔一段时间我就决定以代码高尔夫的形式表达我的疯狂,并且参数允许你使用比普通定义少5个字符来定义本地`int`.:-) (2认同)

Jer*_*fin 17

它是为了与古老的 C编译器向后兼容.在地球冷却之前,所有C函数声明看起来大致如下:

int foo();
long bar();
Run Code Online (Sandbox Code Playgroud)

等等.这告诉那名被称为函数编译器,但并没有指定有关数量或类型的参数什么.原始(1989)C标准中最大的变化可能是添加了"函数原型",它允许声明参数的数量和类型,因此编译器可以检查调用函数时传递的内容.为了保持现有代码的兼容性,他们决定一个空参数列表将保留其现有含义,如果你想声明一个不带参数的函数,你必须添加void代替参数列表:int f(void);.

请注意,在C++中,情况并非如此 - C++消除了旧样式函数声明,并要求指定所有参数的数量和类型1.如果你声明没有参数的函数,这意味着它不接受任何参数,如果你试图传递任何参数,编译器会抱怨(除非你也重载了函数,所以有另一个具有相同名称的函数可以带参数).

1虽然您仍然可以使用省略号来获取带有变量参数列表的函数 - 但是当/如果这样做,您只能将POD类型作为参数传递.


Mat*_*hen 5

您尚未提供该foo函数的原型,因此编译器无法强制执行该函数.

如果你写道:

void foo(void) {}
Run Code Online (Sandbox Code Playgroud)

那么你将提供一个不带参数的函数原型.

gcc -Wstrict-prototypes会抓住这个.如有错误,请使用-Werror=strict-prototypes.标准从不指定某些内容应该是警告还是错误.