Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 这种对非原型函数声明的可疑使用有效吗?_C_Prototype_Standards_Language Lawyer - Fatal编程技术网

C 这种对非原型函数声明的可疑使用有效吗?

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

这是有效的C(C99)代码吗

如果它是
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;