C-直接使用地址访问内存?

时间:2018-07-25 15:06:20

标签: c memory-access

我已经有几本书对C进行了轻松的学习。

int main(void)
{
    float num = 3.15;
    int *ptr = (int *)# //so I can use line 8 and 10

    for (int i = 0; i < 32; i++)
    {
        if (!(i % 8) && (i / 8))
            printf(" ");
        printf("%d", *ptr >> (31 - i) & 1);
    }

    return 0;
}

output : 01000000 01001001 10011001 10011010

单精度3.15中的float01000000 01001001 10011001 10011010。 因此,假设ptr指向地址0x1efb40

以下是问题:

  1. 正如我在书中所了解的那样,num数据的前8位存储在0x1efb40中,0x1efb41中的第二8位存储在{{1}中}和0x1efb42中的后8位。我说的对吗?

  2. 如果我是对的,我有什么办法可以直接使用十六进制地址值0x1efb43访问第二个8位?从而可以将数据更改为类似0x1efb41的内容吗?

3 个答案:

答案 0 :(得分:4)

数据类型中字节的顺序称为 endianness ,并且是系统特定的。首先用最低有效字节(LSB)描述的内容称为 little endian ,这是在基于x86的处理器上可以找到的内容。

对于访问表示形式的特定字节,可以使用指向unsigned char的指针来指向相关变量以查看特定字节。例如:

 float num = 3.15;
 unsigned char *p = (unsigned char *)&num;
 int i;

 for (i=0; i<sizeof(num); i++) {
     printf("byte %d = %02x\n", i, p[i]);
}

请注意,这仅允许通过字符指针而不是int *访问字节,因为后者违反了严格的别名。

答案 1 :(得分:1)

您编写的代码实际上不是有效的C。C有一个称为“严格别名”的规则,该规则指出,如果内存区域包含一种类型的值(即float),则无法访问它。好像它是另一种类型(即int)。此规则起源于一些性能优化,这些性能优化使编译器生成更快的代码。我不能说这是一个明显的规则,但这是规则。

您可以使用union解决此问题。如果创建像union { float num, int numAsInt }这样的并集,则可以存储浮点数,然后将其读取为整数。结果为未指定。另外,始终允许您以char形式访问值的字节(只是没有更大的值)。 char得到了特殊处理(大概是为了使它能够复制,以便您可以将数据缓冲区复制为字节,然后将其强制转换为数据的类型并访问它,这在诸如网络堆栈的低级代码中经常发生)。

欢迎来到学习C的有趣角落。有未指定行为和未定义行为。非正式地,未指定的行为表示“我们不会说会发生什么,但这是合理的。” C规范不会说字节的顺序。但是会说您将得到一些字节。未定义的行为更糟​​糕。未定义的行为表明任何事情都可能发生,从编译器错误到运行时异常,甚至什么都没有(使您认为代码在无效时是有效的)。

对于值,dbush在他的答案中指出字节的顺序由您所使用的平台定义。您会看到IEE754浮点数的“小尾数”表示。在其他平台上,可能有所不同。

答案 2 :(得分:0)

与联盟的合作更加安全:

#include <stdio.h>

typedef     union
    {
        unsigned char uc[sizeof(double)];
        float f;
        double d;
    }u_t;

void print(u_t u, size_t size, int endianess)
{
    size_t start = 0;
    int increment = 1;

    if(endianess)
    {
        start = size - 1;
        increment = -1;
    }

    for(size_t index = 0; index < size; index++)
    {
        printf("%hhx ", u.uc[start]);
        start += increment;
    }
    printf("\n");
}


int main(void) 
{
    u_t u;  
    u.f = 3.15f;

    print(u, sizeof(float),0);
    print(u, sizeof(float),1);

    u.d = 3.15;
    print(u, sizeof(double),0);
    print(u, sizeof(double),1);
    return 0;
}

您可以自己进行测试:https://ideone.com/7ABZaj