将char指针转换为int指针 - 缓冲区错误10

时间:2014-07-24 21:21:57

标签: c pointers casting

在这个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中工作。

5 个答案:

答案 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标准进行修复。)