C 这种对非原型函数声明的可疑使用有效吗?
这是有效的C(C99)代码吗 如果它是C 这种对非原型函数声明的可疑使用有效吗?,c,prototype,standards,language-lawyer,C,Prototype,Standards,Language Lawyer,这是有效的C(C99)代码吗 如果它是f(intx,…)并且它查看它的第一个参数的符号以知道它得到了多少(0或1)个vararg,该怎么办?它是有效的(好吧,它可能取决于您使用的标准)。你应该读一些关于 基本上,如果f只接受一个参数或不接受任何参数,我希望不会出现问题。 如果f接受两个或多个参数,那么这些其他参数(第一个参数除外)可能会有垃圾值(显然是随机的) 考虑这段代码: int f(int x, int y); int g(int x) { int k; //No value
f(intx,…)
并且它查看它的第一个参数的符号以知道它得到了多少(0或1)个vararg,该怎么办?它是有效的(好吧,它可能取决于您使用的标准)。你应该读一些关于
基本上,如果f
只接受一个参数或不接受任何参数,我希望不会出现问题。如果
f
接受两个或多个参数,那么这些其他参数(第一个参数除外)可能会有垃圾值(显然是随机的)
考虑这段代码:
int f(int x, int y);
int g(int x)
{
int k; //No value
if (x<0) return f(x, k);
else return f(x, x);
}
intf(intx,inty);
整数g(整数x)
{
int k;//没有值
如果(x让我们换一种方式问:为什么它不有效?我真的找不到任何禁止上述代码的参数或规则。在相应的其他分支中的函数调用从未执行过(尽管注释中的讨论表明这不是那么容易!)。C99(6.5.2.2函数调用,第8项)表示如果函数定义没有原型,则参数和参数的数量和类型“不会进行比较”
我见过这种(ab)在野外与函数指针一起使用。void(*)(
数组包含void(*)(struct Client*)
和void(*)(struct Client*,int parc,char*parv[])
函数指针。根据数组索引,代码是否传递了额外的参数
在这种情况下,编译器没有(合理的)方法提前检查参数的数量,即使它有所有相关的代码
我认为这是肮脏的代码,我修复了那个特定的实例。我同意,只要C抽象机从未对不正确的函数调用求值,它就是有效的
不过,还有另一种更简单的方法可以得出关于链接器的结论:因为这是允许的:
int f();
int (*fp)() = f;
链接器必须能够在不知道其实际定义的情况下找到f()
的地址。因此,必须能够在不知道其实际定义的情况下确定其符号。这肯定不会编译,更不用说链接了。@Oli Charlesworth:你试过了吗?它为我编译和链接。(gcc-std=c99-Wall-Wextra-pedantic无错误或警告@ OLI:你是否混淆了C和C++?当然,在链接时,没有一个真正关心C函数签名的真实世界链接器。如果我的问题中的用法是有效的,我怀疑它是一个证明,即链接器不被允许关心签名。@ Oli Charlesworth:你必须用一个参数调用一个函数。与定义该函数时使用的参数兼容。调用该函数时,不必在作用域中有原型(有些例外)。请注意,int f();
是函数的声明,但不是原型。@Charles:那么,我今天学到了一些新东西!(即int f();
是有效的,并且与int f(void)不同;
)那么它是未定义的行为,因为函数是用,…
声明的,在没有原型的情况下调用的。Charles说的。可变函数绝对需要原型。也许更令人兴奋的是,如果它是f()
,第一个参数的符号告诉它有多少个参数,函数实际上是在汇编程序中实现的,而不是在C中实现的,它知道C调用约定,因此它可以在不使用varargs的情况下读取正确的参数?如果此代码无效,您不能这样做,但正如R在上面的注释中所说,实际上没有链接器ce会不遗余力地阻止它。@Steve:在编写和链接asm时,您已经超出了C的范围,并且在特定实现的范围内,这几乎肯定允许我编写代码。我更感兴趣的是从标准的角度来看,以及这对实现的要求(例如,一个不基于参数类型损坏函数名的要求)。@R:很公平,我只是认为这是人们希望标准允许它的另一个原因,这是本建议的精神。int f(…);
是完全无效的。无法在标准C中编写一个以单个…
作为参数的函数,并将非变量函数原型化为变量函数,反之亦然,或者根本无法原型化变量函数,都会导致未定义的行为。如果rguments与函数调用中的参数数量不匹配。问题是,如果程序中没有实际计算,那么在程序中使用这样的表达式是否有效。谢谢你,查尔斯。如果可以的话,我会给出+10的注释,因为你在一句话中表达我的问题比在整个原始问题中表达得更好。@R..Hmm。你是正确。我想我很久以前在某个地方读过它,但我也发现一个源代码声明它无效。我将删除该部分。具体取决于参数array[n]即使n
有一个负值,
也可能是有效的。如果array
中有一个数组而不是指针,这将是一个更令人信服的例子。如果我声明int f(),h();
并执行if(顺便说一句,我同意你的推理,我认为如果它是正确的,那么它意味着实现无法执行任何C++之类的符号名称篡改或基于函数签名的其他技巧。我更喜欢你的旧示例代码。在你的新示例(1)中,不清楚省略返回是什么意思,(2)除非调用者使用返回值,否则从函数末尾运行不是未定义的行为,并且(3)除了最微小的参数外,您的新函数在所有参数上都有严重的UB(整数溢出):-@R..i替换了它,因为数组[n]
示例依赖于运行时数据(值n
)。但是,新示例不依赖于运行时数据:
int f(int x, int y);
int g(int x)
{
int k; //No value
if (x<0) return f(x, k);
else return f(x, x);
}
int f();
int (*fp)() = f;