#include <stdio.h>
int fun1(void);
int fun2(void);
int fun3(void);
int x; //global variable
void main(){
x=10;
printf("x = %dn",x);
printf("x = %dn",fun1());
printf("x = %dn",fun2());
printf("x = %dn",fun3());
}
fun1(void){
x = x+10; //global
}
fun2(void){
int x;
x = 1; //local
return x;
}
fun3(void){
x = x+10; //local
}
输出:
x = 10
x = 20
x = 1
x = 30
在典型的C函数中,将传递的参数在编译时是已知的。它们在函数定义和函数声明(如果有的话)中声明。
编译器在此基础上生成代码,并进行编译时检查,以便如果您传递了一个意外的参数或错误的类型之一,编译器将注意并输出错误或警告。
但是printf
不是这样工作的。
像printf
这样的函数在每次调用时都能够处理不同数量和类型的参数,而不需要知道这些参数在编译时是什么。
这些被称为variadic
函数,而不是显式地声明它们的参数,它们使用宏,如va_start
,va_arg
,va_end
,以便在运行时获取参数。下面是这些宏的手册页:
https://linux.die.net/man/3/va_arg
通过在格式字符串中使用%d
,您已经向printf
函数承诺,在格式字符串之后传递的第一个参数将是整数。但是在您的代码中,您没有这样做。你的代码违背了它对printf
的承诺,但printf
没有办法知道…它只会使用va_arg
宏从内存位置获取一个整数值。
因为你没有把整型放在它应该在的地方,它抓取的值将是碰巧在那个内存位置的任何值,这可能是完全的垃圾。
在C规范中,这就是所谓的"未定义行为"。它的意思很简单,就是不支持这样做,而且C语言根本不能保证如果这样做会发生什么。
在高级语言中,例如在Python中,有更多的运行时检查,并且打印函数可以在运行时确定您传递了多少参数及其类型。但在c中不是这样。您必须确保传递给printf
的参数的数量和类型与格式字符串中指示的完全匹配,并且顺序相同。
在你的代码中,因为你的格式字符串表明将传递一个整数,但你没有传递一个整数,你不能指望它能正确工作,它只是"未定义的行为"。