我正在使用gcc并编写了一个小程序,如下所示:
#include<stdio.h>
void doing(){
char buf[4096 + 1];
printf("buf %d\n", buf);
printf("buf %f\n", buf);
printf("buf %d\n", (unsigned) buf);
printf("buf %s\n", buf+2);
printf("buf %d\n", buf+2);
}
int main (void){
char buf[4096 + 1];
printf("(unsigned) buf %d\n", (unsigned) buf);
doing();
printf("(unsigned) buf %d\n", (unsigned) buf);
return 0;
}
该计划的输出是:
(unsigned) buf 2268303
buf 2264159
buf 0.000000
buf 2264159
buf
buf 2264161
(unsigned) buf 2268303
我不知道为什么将2268303打印为整数,并且从这个2268303值开始,其中一个函数的值是2268303,另一个是2264159
答案 0 :(得分:1)
请阅读C基础知识。你会得到答案。
关于,
一个函数的值为2268303,另一个为2264159
注意到,一个char buf []在main()中声明,另一个在do()中。两者都有不同的存储空间,两者都可以在自己的范围内工作[阅读C中变量的范围]
答案 1 :(得分:1)
让我们分解一下,看看我们可以对每行代码说一遍,一个接一个:
int main (void){
char buf[4096 + 1];
您声明一个char[4097]
,通常在输入main
时通过调整堆栈指针在堆栈上分配。数组的内容是不确定的。
printf("(unsigned) buf %d\n", (unsigned) buf);
数组类型的表达式,除非它是地址(&
),sizeof
或_Alignof
运算符的操作数,或者它是用于初始化字符数组的字符串文字,被转换为指向数组第一个元素的指针(6.3.2.1 p.3),因此该行等同于
printf("(unsigned) buf %d\n", (unsigned) &buf[0]);
获取buf
中第一个字节的地址,将其转换为unsigned
并将结果数字打印为有符号整数。请注意,如果生成的unsigned
值无法表示为int
,则行为未定义。指针&buf[0]
到unsigned
的转换是实现定义的,可能会调用未定义的行为(6.3.2.3第6页)。通常,指针值的sizeof(unsigned)
字节被解释为无符号整数(通常包括指针的大小不小于unsigned
的大小)。在您的情况下,结果是
(unsigned) buf 2268303
被打印出来了。下一步
doing();
让我们看一下doing
:
void doing(){
char buf[4096 + 1];
声明了另一个char[4097]
,通常在输入doing
时通过调整堆栈指针来分配它。这个数组的内容也是不确定的。
printf("buf %d\n", buf);
同样,buf
类型的char[4097]
表达式转换为char*
,即&buf[0]
,并传递给期望printf
的{{1}} {1}}论点。类型不匹配调用未定义的行为,指针值的int
字节通常被解释为有符号整数。结果是ouptut
sizeof(int)
强烈暗示buf 2264159
中的buf
被分配了距离doing
4144个字节,并且堆栈向下增长。
main
我们再次进行了数组到指针的转换,现在 printf("buf %f\n", buf);
需要一个printf
参数但得到double
。更多未定义的行为,表现形式是
char*
已打印。一般来说(毕竟,它是未定义的行为)无法回答,在64位系统上,常见的行为是指针或整数类型的buf 0.000000
参数在通用寄存器和浮点参数中传递在浮点寄存器中,以便printf
读取浮点寄存器 - 恰好包含0值。
printf
这一行与 printf("buf %d\n", (unsigned) buf);
的对应行具有相同的语义,但由于它是一个不同的数组main
,因此从转换中获得的(无符号)整数是不同的。
buf
它与buf 2264159
中的第一个printf
打印相同,这并不奇怪(但不能保证,因为涉及未定义的行为)。
doing
printf("buf %s\n", buf+2);
转换为buf
,然后向其添加2,结果为&buf[0]
。这传递给&buf[2]
,由于printf
转换需要一个指向0终止的%s
数组的指针作为参数。这是整个程序中唯一的char
调用,printf
的第二个参数的类型与转换说明符的预期类型完全匹配。但printf
的内容是不确定的,因此如果数组中没有0字节,则会导致buf
无效读取。但是,显然printf
为0,所以只是
buf[2]
被打印出来了。
buf
printf("buf %d\n", buf+2);
再次评估为buf + 2
,并在&buf[2]
期望printf
的位置传递。类型不匹配会调用未定义的行为,但输出
int
表示没有发生任何恶意,因为buf 2264161
比&buf[2]
落后两个字节,所打印的数字比&buf[0]
首先doing
中打印的数字大两倍
printf
返回}
:
main
该行与 printf("(unsigned) buf %d\n", (unsigned) buf);
中的第一个printf
调用相同,因此它具有相同的语义,如上所述,
main
并产生相同的输出。
(unsigned) buf 2268303
答案 2 :(得分:0)
如果您使用%p
,则会获得hex
个值。
您还需要了解scope。也可以浏览these links。
(unsigned) buf 2268303 // You have defined this in main its a local array so it has
//2268303 as address. And for an array the array name acts as a
//pointer too
buf 2264159 // You have defined this in fn doing, it is local to that function
//and has a different address (it is a different array than the one
//in your main)
答案 3 :(得分:0)
以下是解释:
此:
printf("buf %d\n", buf);
将打印“buf”数组
上第一个元素的地址(内存位置)此:
printf("buf %f\n", buf);
将尝试从“buf”数组的第一个元素的地址读取一个浮点数,printf可能返回零,因为它不知道如何处理它。
此:
printf("buf %d\n", (unsigned) buf);
将与第一个printf相同,因为“buf”的地址总是大于或等于零。
此:
printf("buf %s\n", buf+2);
将尝试从“buf”数组的第一个元素的地址读取一个浮点数,printf可能返回一个空字符串,因为它不知道如何处理它。
最后:
printf("buf %d\n", buf+2);
返回“buf”数组
中第三个元素的位置需要注意的重要事项: 您声明的两个“buf”数组(一个在main中,另一个在done()内)是两个不同的数组,即使您给它们指定了相同的名称。 在do()中,“buf”指的是你在那里创建的那个,在主“buf”里面也指你在那里创建的那个。这就是为什么从内部打印或主要打印时获得两个不同地址的原因