C 隐式声明和varargs函数之间的冲突 extern int identifier();

C 隐式声明和varargs函数之间的冲突 extern int identifier();,c,C,有人能确认标准中关于vararg函数的默认返回类型的说法吗。我正在编译以下代码: int main() { maw(32,3,95,38,20,15); return 0; } int maw(int a,int b,...) { int *p=&b,i=0; while(i++<a) printf("\t%d",*p++); return 0; } 但是如果在定义maw的过程中,如果我把它称为voidMAW(inta,in

有人能确认标准中关于vararg函数的默认返回类型的说法吗。我正在编译以下代码:

int main()
{
    maw(32,3,95,38,20,15);
    return 0;
}

int maw(int a,int b,...)
{
    int *p=&b,i=0;
    while(i++<a)
       printf("\t%d",*p++);
    return 0;
}
但是如果在定义maw的过程中,如果我把它称为
voidMAW(inta,intb,…)
编译是非常好的

extern int identifier(); 我可以从中看出,vararg函数的默认返回类型可能不是
int

标准对此有何规定?有人能帮我确认一下吗


我知道,如果我只是标准化代码,它将运行得非常完美。我已经做到了。这没有问题

我的观点是:这个代码有什么问题?它应该运行得很好。 像这样的代码运行时不会出现任何错误吗

int main()
{

abc();
.....
return 0;
}

abc()
{
.......
}
当使用可变参数函数时,问题就来了。
我知道标准对函数的默认定义是什么。

在main()之前声明maw(),或者在main()之前创建原型。函数返回指定给它们的类型,而不考虑参数(变量或非变量)。

在main()之前声明maw(),或在main()之前创建原型。函数返回您分配给它们的类型,而不管参数(变量或非变量)。

问题在于您在定义函数之前调用它,而不包括声明。如果您添加这样一行:

int maw(int a, int b, ...);
extern int identifier();
在使用
main()
函数之前,您会没事的。默认(“implcit”)是假定函数返回
int
,并且具有空参数列表。依赖隐式声明的形式不好,您应该显式声明所有函数。

问题是,您在定义函数之前调用函数,而不包括声明。如果您添加这样一行:

int maw(int a, int b, ...);
extern int identifier();
在使用
main()
函数之前,您会没事的。默认(“implcit”)是假定函数返回
int
,并且具有空参数列表。依赖隐式声明是一种不好的形式,您应该显式声明所有函数。

这与返回类型无关-事实上您声明了它。提出声明:

int maw(int a,int b,...);
extern int identifier();
在使用main()中的函数之前,它与返回类型无关,而是您声明了它。提出声明:

int maw(int a,int b,...);
extern int identifier(); 在使用main()中的函数之前,请添加声明

int maw(int a,int b, ...);
extern int identifier(); 在
main()
函数之前

目前,您在
main()
函数中进行的调用隐式定义了
maw()
,也就是说,编译器根据
main()
中给出的信息“猜测”什么是
maw()
的返回类型。如果在调用前声明
maw()
,则不会出现此问题。

添加声明

int maw(int a,int b, ...);
extern int identifier(); 在
main()
函数之前


目前,您在
main()
函数中进行的调用隐式定义了
maw()
,也就是说,编译器根据
main()
中给出的信息“猜测”什么是
maw()
的返回类型。如果在调用函数前声明
maw()
,则不会出现此问题。

关于将函数原型放在第一位,其他答案是正确的

extern int identifier();
此外,为了便于移植,请不要使用指向最后一个(非vararg)参数的直接指针来访问
参数,因为这样您就必须关心目标平台的对齐方式和堆栈方向。相反,使用
va.*
宏来处理varargs。

关于将函数原型放在首位,其他答案是正确的

此外,为了便于移植,请不要使用指向最后一个(非vararg)参数的直接指针来访问
参数,因为这样您就必须关心目标平台的对齐方式和堆栈方向。相反,使用
va.*
宏来处理varargs。

正如每个答案(到目前为止)所说的那样:为了避免错误,在使用函数之前声明它,正如Chris Jester Young指出的那样,使用标准机制来访问变量参数,或者忍受未定义行为的痛苦

在本例中,不是因为函数的返回类型而需要在本例中使用前声明,而是因为它与未声明函数的默认签名不匹配:
int u()
;也就是说,使用未指定参数的函数返回
int
。具体而言,实际定义
int-maw(int,int,…)
与假定声明
int-maw()
不一致,这导致GCC说“maw的冲突类型”

extern int identifier(); 你的第二个例子

int main() {
  abc(); ..... return 0; 
}
abc() { ....... }
之所以有效,是因为后面对abc的定义与第一次调用时假定的默认签名不矛盾。但是仅仅因为它可以工作并不能使它成为一种好的形式,因为默认签名几乎没有类型安全性

访问可变参数(与
..
匹配的参数)确实应该通过
stdarg.h
的标准机制完成,除非您正在实现一个编译器并且是该编译器的
stdarg.h
的作者。例如,在某些体系结构上,这些参数甚至可能不会在堆栈上传递,但它们仍然可以由
stdarg.h
中的宏定位

编辑:我改写了第二段,以一种不同的方式表达我的意思,我希望更清楚

在第一次调用之前,编译器需要知道函数是可变的,因为在某些体系结构上,可能需要传递不同于普通参数的可变参数。对于某些寄存器窗口风险体系结构,以及那些可能通过寄存器中的前2个整数和前2个浮点数,但必须将所有