在这个answer中,作者讨论了如何在C中转换指针。我想尝试一下并构造这段代码:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
这会编译(带有警告),当我执行二进制文件时,它只输出bus error: 10
。我知道char的大小比int小。我也从post了解到我应该期待这个错误。但是,如果有人能澄清这里发生的事情,我真的很感激。另外,我想知道是否有正确的方法来转换指针并取消引用int指针以获得10(在本例中)。谢谢!
编辑:为了澄清我的意图,如果你担心,我只是想提出一个&#34;工作&#34;指针转换的示例。这只是为了表明这是允许的,可能在C中工作。
答案 0 :(得分:3)
c
未初始化。这是未定义的行为。
同样,即使c
被初始化,你对它的类型转换为int *
然后取消引用会从内存中获得一些额外的字节,这也是未定义的行为。
一个工作(安全)示例,说明了您正在尝试的内容:
int main(void)
{
int i = 10;
int *p = &i;
char c = *(char *)p;
printf("%d\n", c);
return 0;
}
此程序将在小端机器上打印10
,在大端机器上打印0
。
答案 1 :(得分:2)
这些代码行存在问题。您正在通过未初始化的指针进行编写。
char *c;
*c = 10;
改为这样:
char * c = malloc (sizeof (char));
然后,以下行是无效逻辑,编译器至少应该警告你:
int i = *(int*)(c);
您正在从只有一个存储字节(sizeof(char))的指针读取一个int(可能是4或8个字节)。你不能从char内存插槽读取一个int值的字节。
答案 2 :(得分:1)
我知道char的大小比int小。我也从这篇文章中了解到我应该期待这个错误。但是,如果有人能澄清这里发生的事情,我真的很感激
某些体系结构(如SPARC和某些MIPS)需要严格对齐。因此,如果你想读或写一个单词,它必须在4个字节上对齐,例如它的地址是4的倍数,否则CPU将引发异常。像x86这样的其他架构可以处理未对齐的访问,但性能成本却很高。
答案 3 :(得分:1)
首先,您的程序具有未定义的行为,因为指针c
未初始化。
关于这个问题,你可以简单地写一下
int i = *c;
printf("%d", i);
具有小于int类型等级的ranke的积分类型将被提升为表达式中的int类型。
答案 4 :(得分:1)
让我们拿你的代码,找到事情发展的所有地方以及原因,并做最小的修复:
#include <stdio.h>
int main(void) {
char *c;
*c = 10;
前一行是Undefined Behavior (UB),因为c
并未指向至少一个char
- 对象。所以,在这之前直接插入这两行:
char x;
c = &x;
让我们继续修复:
int i = *(int*)(c);
现在这条线也很糟糕。
假设你不是指更合理的隐式扩展转换,让我们的生活变得复杂; int i = c;
:
如果实现定义_Alignof(int) != 1
,则演员调用UB,因为x
可能未对齐。
如果实现定义sizeof(int) != 1
,则解除引用会调用UB,因为我们引用的内存不存在。
让我们通过更改定义x
的行并将其地址分配给c
来解决这两个问题:
_Alignas(in) char x[sizeof(int)];
c = x;
现在,读取解除引用的指针会导致UB,因为我们将某些内存视为存储类型int
的对象,除非我们从有效的int
变量中复制一个,否则这不是真的 - 将两者都视为字符的缓冲区 - 或者我们最后在那里存储了int
。
因此,在阅读之前添加商店:
*(int*)c = 0;
继续......
printf("%d", i);
return 1;
}
回顾一下,改变的程序:
#include <stdio.h>
int main(void) {
char *c;
_Alignas(in) char x[sizeof(int)];
c = x;
*c = 10;
*(int*)c = 0;
int i = *(int*)(c);
printf("%d", i);
return 1;
}
(使用C11标准进行修复。)