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

C - access memory directly using address?

我已经用一些书简单地学习了几个星期的 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 中,第二个 8 位存储在 0x1efb41 中,接下来的 8 位存储在0x1efb420x1efb43 中的最后 8 位。我说的对吗?

  2. 如果我是对的,有什么方法可以直接访问具有十六进制地址值0x1efb41的第二个8位?因此我可以将数据更改为 11111111?

数据类型中的字节顺序称为 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 *,因为后者违反了严格的别名。

您编写的代码实际上不是有效的 C。C 有一个名为 "strict aliasing," 的规则,该规则规定如果内存区域包含一种类型的值(即 float),它不能就像它是另一种类型一样被访问(即 int)。这条规则起源于一些让编译器生成更快代码的性能优化。我不能说这是一个明显的规则,但这是规则。

您可以使用 union 解决此问题。如果你创建一个像 union { float num, int numAsInt } 这样的联合,你可以存储一个浮点数,然后将它作为一个整数读取。结果是未指定。或者,始终允许您以字符形式访问值的字节(只是不能更大)。 char 被给予特殊处理(大概是为了让您可以将数据缓冲区复制为字节,然后将其转换为您的数据类型并访问它,这在网络堆栈等低级代码中经常发生).

欢迎来到学习 C 的有趣角落。有 未指定 行为和 未定义 行为。非正式地,未指定的行为表示 "we won't say what happens, but it will be reasonable." C 规范不会说明字节的顺序。但它会说您将获得一些字节。未定义的行为更糟​​糕。未定义的行为表明 任何事情 都可能发生,从编译器错误到运行时的异常,再到完全没有(让你认为你的代码有效,但实际上却不是)。

至于值,dbush 在他的回答中指出字节的顺序是由您所在的平台定义的。您看到的是 IEE754 浮点数的 "little endian" 表示。在其他平台上,可能会有所不同。

联合双关更安全:

#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