【发布时间】:2010-09-20 06:44:06
【问题描述】:
int i=40;
char *p;
p=(char *)&i;//What actually happens here?
printf("%d",*p);
输出会是什么?请帮忙!
【问题讨论】:
int i=40;
char *p;
p=(char *)&i;//What actually happens here?
printf("%d",*p);
输出会是什么?请帮忙!
【问题讨论】:
p=(char *)&i;//What actually happens here?
它获取i 的地址并将其转换为char 指针。所以*p 的值现在是i 的第一个字节。该值是什么,取决于平台。
【讨论】:
char *p = (char *) &i 和char *p = &i 有什么区别?
让我们先看看i 和p 的内容在内存中的布局方式(假设大端顺序):
由于p 被声明为自动变量,它没有被初始化为任何东西并且包含由0x?? 表示的随机位模式。
排队
p = (char *)&i;
表达式&i 的计算结果为i 或0x08000000 的地址,其类型为pointer to int 或int *。强制转换将类型从int * 转换为char *,并将结果分配给p。
这是分配后内存中的情况:
项目地址 0x00 0x01 0x02 0x03 ---- -------- ---------- 我 0x08000000 0x00 0x00 0x00 0x28 p 0x08000004 0x08 0x00 0x00 0x00所以p 的值现在是i 的地址。在行中
printf("%d", *p);
表达式*p 的类型是char,它的值是存储在地址0x08000000 中的任何值,在本例中为0。由于printf 是一个可变参数函数,所以*p 的值从char 类型提升为int 类型。
所以对于这种特殊情况,输出为“0”。如果顺序是 little-endian,则地图看起来像
项目地址 0x03 0x02 0x01 0x00 ---- -------- ---------- 我 0x08000000 0x00 0x00 0x00 0x28 p 0x08000004 0x08 0x00 0x00 0x00输出将是“40”。
请注意,整个示例假定整数和字符指针具有相同的大小和布局;这不能保证在任何地方都是正确的(参见Online C Standard (n1256 draft),第 6.2.5 节,第 27 段),所以你不能依赖它在任何地方按照你期望的方式工作(假设我认为int 和char 不是标准定义的兼容类型,但我可能错了)。类型双关语通常是不安全的。
【讨论】:
int* 和char* 指针具有相同的大小和布局,但程序的可见行为却不同。 C 标准保证任何对象都可以作为字符数组访问,因此 OP 的代码将访问i 的第一个(最低地址)字节。正如其他人指出的那样,该字节的值取决于实现。
char *p = (char *) &i 和 char *p = &i 有什么区别?
char *p = (char *) &i 和char *p = &i 有什么区别?
char *p = (char *) &i;islegal,而char *p = &i;不是。 char* 和 int* 之间没有隐式转换(尽管某些编译器可能允许这样做,最好带有警告)。指针转换可能很危险,让您将一种类型的对象视为另一种类型,因此语言要求此类转换是显式的。
你来了
int i = 40; //为整数i分配内存并赋值为40
char *p = (char*)&i;
所以在这里你定义了一个指针变量,并在将其转换为char* 后为其分配 i 的地址
假设i 分配在1021 address,那么p 将拥有限制为1 字节的地址,因此它应该保存first 8 bit from the representation of 40;
由于 40 已被 2 字节的前 8 位覆盖,它将持有 40 的 char 等效值,但当您使用 %d 打印它时,它会打印 40;
【讨论】:
char *p = (char *) &i 和char *p = &i 有什么区别?
这取决于。在 Windows 上,输出将是 40,但这只是因为很多巧合:
首先,printf 不(不能)检查其参数的类型,因此由于它在格式字符串中看到 %d,它假定给定的参数是一个 int。虽然 *p 只是一个字符,但结果会被提升为一个 int(对于函数原型中未指定的每个参数也是如此)。
其次,p会指向变量i占用的内存,但是由于它是一个char指针,所以它只会从i的内存中占用一个字节。由于 Windows/Intel 使用 Least-Significant-Byte 第一个约定,40 将存储为字节模式“40 0 0 0”,因此,由于 *p 采用第一个字节(char),结果将为 40。如果我有值 256 或更大,结果将不正确。
What happens when int pointer is typecasted to char? 还有一个问题标记为重复到这里,我试着解释一下。
$ cat a.c
#include <stdio.h>
int main(){
int a;
char *x;
x = (char *) &a;
a=512;
x[0]=1;
x[1]=2;
printf("%d\n",a);
return 0;
}
编译运行:
$ gcc a.c && ./a.out
513
为什么是 513?我们可以使用 gdb 来查看根本原因。
$ gcc a.c -g && gdb ./a.out
(gdb) list
1 #include <stdio.h>
2
3 int main(){
4 int a;
5 char *x;
6 x = (char *) &a;
7 a=512;
8 x[0]=1;
9 x[1]=2;
10 printf("%d\n",a);
在 a.c 的第 8 行设置断点,然后运行
(gdb) b a.c:8
Breakpoint 1 at 0x40113d: file a.c, line 8.
(gdb) run
一旦程序在断点处停止,打印变量a的内存地址。
(gdb) p &a
$2 = (int *) 0x7fffffffd9d4
(gdb) p x
$3 = 0x7fffffffd9d4 ""
变量a的内存地址为0x7fffffffd9d4,变量x的值相同。
在显示内存内容之前,我们先来了解一下16进制格式的512,它是:
00 00 02 00
x86 是小端,所以在内存中应该是:
[higher address] 00 02 00 00 [lower address]
让我们展示真实的记忆,就像我们想象的一样。
(gdb) x/4xb 0x7fffffffd9d4
0x7fffffffd9d4: 0x00 0x02 0x00 0x00
然后,显示x[0]和x[1]的内存地址,并将内存内容转换为实际值,应该不难理解为什么会打印出513。
(gdb) p &x[0]
$4 = 0x7fffffffd9d4 ""
(gdb) p &x[1]
$5 = 0x7fffffffd9d5 "\002"
【讨论】: