什么';C将地址转换为int的规则是什么?
我是C语言的初学者,今天我在学习指针部分,我发现我可以直接打印地址,当使用正确的类型转义符时,我甚至可以打印存储在该内存地址中的预期值 后来,我做了一些实验:什么';C将地址转换为int的规则是什么?,c,C,我是C语言的初学者,今天我在学习指针部分,我发现我可以直接打印地址,当使用正确的类型转义符时,我甚至可以打印存储在该内存地址中的预期值 后来,我做了一些实验: ##### CODE PART ###### #include <stdio.h> // Define several variable types, macros, and functions about standard input/output. int main () { char my_string[]
##### CODE PART ######
#include <stdio.h> // Define several variable types, macros, and functions about standard input/output.
int main () {
char my_string[] = "address test";
printf("%s\n", &my_string);
printf("%p\n", &my_string);
printf("%d\n", &my_string);
printf("%x\n", &my_string);
printf("\n");
char *p = "pointer string test";
printf("%s\n", p);
printf("%p\n", p);
printf("%d\n", p);
printf("\n");
char *p2 = 'p';
printf("%c\n", p2);
printf("%p\n", p2);
printf("%d\n", p2);
return 0;
}
##### OUTPUT #####
address test
0x7fff58778a7b
1484229243
58778a7b
pointer string test
0x107487f87
122191751
p
0x70
112
代码部分######
#包括//定义几个关于标准输入/输出的变量类型、宏和函数。
int main(){
char my_string[]=“地址测试”;
printf(“%s\n”&我的字符串);
printf(“%p\n”&我的字符串);
printf(“%d\n”&我的字符串);
printf(“%x\n”&我的字符串);
printf(“\n”);
char*p=“指针字符串测试”;
printf(“%s\n”,p);
printf(“%p\n”,p);
printf(“%d\n”,p);
printf(“\n”);
char*p2='p';
printf(“%c\n”,p2);
printf(“%p\n”,p2);
printf(“%d\n”,p2);
返回0;
}
#####输出#####
地址测试
0x7fff58778a7b
1484229243
58778a7b
指针字符串测试
0x107487f87
122191751
P
0x70
112
起初我不太了解%d
格式输出的行为,但经过更多的观察和实验之后。我发现%d
正在转换内存地址的部分十六进制值
但是对于my_字符串的地址
它省略了0x7fff
部分,对于p
的地址它省略了0x10
部分,对于p2
它省略了0x
部分。在我的认知中,0x
是十六进制值的头符号
但是,我怎么知道在将内存地址转换为int时,C会省略多少位,就像在my_string
和p
的示例中一样
PS:我的系统版本是OSX10.10,没有规则。这不包括在C标准中。你的代码会导致。你在整个项目中观察到的任何结果都是毫无意义的 使用
printf
时,必须自己将参数转换为正确的类型
printf("%d\n", &my_string);
printf("%x\n", &my_string);
是未定义行为的原因。格式说明符和参数类型必须匹配,printf
才能正常工作。有关有效格式说明符及其应用的数据类型的列表,请参阅
以下几行也有同样的问题
printf("%d\n", p);
printf("%c\n", p2);
printf("%d\n", p2);
线路
char *p2 = 'p';
将表示字符'p'
的整数值指定给p2
。但是,这不是一个有效的地址
可用于固定指针的整数类型有intptr\u t
和uintpr\u t
。因此,您可以使用:
char my_string[] = "address test";
intptr_t ptr = &my_string;
但是,不能使用%d
格式说明符打印该值。您需要使用:
printf("%" SCNdPTR "\n", ptr);
把它打印出来
查看更多详细信息。C标准(ISO/IEC 9899:2011)对指针和整数之间的转换有如下规定:
6.3转换
6.3.2.3指针
^5整数可以转换为任何指针类型。除非前面指定,否则结果是实现定义的,可能没有正确对齐,可能没有指向引用类型的实体,可能是陷阱表示。67)
^6任何指针类型均可转换为整数类型。除非前面指定,否则结果是实现定义的。如果结果不能用整数类型表示,则行为未定义。结果不必在任何整数类型的值范围内
67)用于将指针转换为整数或将整数转换为指针的映射函数旨在
与执行环境的寻址结构保持一致
请注意,指针和整数之间的转换行为是实现定义的,而不是未定义的。但是,除非使用的整数类型是uintpr\u t
或intptr\u t
(从
-或
),否则如果指针的大小与整数类型不匹配,则可能会看到截断效果。如果您在32位和64位系统之间移动代码,您将在某个地方遇到问题
在代码中,您有64位指针(因为您在Mac OS X 10.10上,需要显式指定-m32
,以获得32位构建,但您的结果与64位构建是一致的)。当您使用%d
和%x
转换规范将这些指针传递到printf()
时,您正在请求printf()
打印32位数量,因此它将格式化传递的64位中的32位。行为不明确;从本质上讲,您没有得到转换,但是调用代码(在main()
)将64位指针推送到堆栈上,而被调用代码(printf()
)从堆栈中读取32位的量。如果您请求对printf()
的单个调用应打印多个值(例如printf(“%d%x\n”,p,p);
),您将得到更令人惊讶的结果
您应该使用以下选项进行编译:
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror …
使用这些选项,您的代码将无法编译;编译器会抱怨格式字符串和传递的值之间不匹配。当我将您的代码保存到一个文件noise.c
中,并使用clang
编译它时(来自运行在Mac OS X 10.10.5上的XCode 7.2),我得到:
使用严格的警告编译,并注意这些警告。没有像“十六进制值”这样的东西。数字就是数量。十进制和十六进制只是使用不同约定表示数字。人们也可以用罗马数字来表示数字,其值仍然保持不变 变量的地址是一个概念,而不是一个物理对象。在当前的操作系统和CPU架构上,这通常是一个(大)数字,但这并不是一成不变的 根据编译器及其编译的代码,变量可以存储在内存中(其地址看起来像一个大整数),也可以不存储。编译器可以优化代码并在CPU寄存器中存储临时变量;在这种情况下,它不会
$ /usr/bin/clang -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition -Werror noise.c -o noise
noise.c:5:20: error: format specifies type 'char *' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%s\n", &my_string);
~~ ^~~~~~~~~~
noise.c:7:20: error: format specifies type 'int' but the argument has type 'char (*)[13]' [-Werror,-Wformat]
printf("%d\n", &my_string);
~~ ^~~~~~~~~~
noise.c:8:20: error: format specifies type 'unsigned int' but the argument has type 'char (*)[13]'
[-Werror,-Wformat]
printf("%x\n", &my_string);
~~ ^~~~~~~~~~
noise.c:14:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p);
~~ ^
%s
noise.c:17:11: error: incompatible integer to pointer conversion initializing 'char *' with an expression of
type 'int' [-Werror,-Wint-conversion]
char *p2 = 'p';
^ ~~~
noise.c:18:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%c\n", p2);
~~ ^~
%s
noise.c:20:20: error: format specifies type 'int' but the argument has type 'char *' [-Werror,-Wformat]
printf("%d\n", p2);
~~ ^~
%s
7 errors generated.
$