微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

不能完全理解使用void * / char *引用和int +指针算法的非常小的C程序的输出

如何解决不能完全理解使用void * / char *引用和int +指针算法的非常小的C程序的输出

我无法完全理解为什么当我期望垃圾值/崩溃值时,onlinegdb.com和Visual Studio上的以下代码段的输出2

我知道小端和大端是什么。我的comp很明显应该是低位字节序,因为它是32位Intel Core Duo。

我有512个,在小尾数法中是:

0000 0000 0010 0000 0000 0000 0000 0000
^         ^         ^
p         p+1       p+2

p指向第一个0000p + 1指向0010。当我打印2时来自0010,但是使用%d时,它应该不打印0010 0000 0000 0000 0000 0000 xyzw rstu的十进制表示形式(带有8个随机位)吗?

Q:是认将最后一位修补为0还是只是运气好,取0导致它们使用了最后一个值?应该不是不确定的吗?

#include <stdio.h>

int main()
{
    int x = 512;
    void *p = &x;
    printf("%d\n",*((char*)p + 1));
    return 0;
}

解决方法

使用%d是否应该不打印0010 0000 0000 0000 0000 0000 xyzw rstu(8个随机位)?

不,不是您的情况。

您正在这样做:

*((char*)p + 1)

含义如下:

  1. p并将其投射到char *
  2. 前进1个位置(广播到char *表示1个字节)。
  3. 取消引用(仍为char *),获取1个字节。
  4. 您获得的字节为2。
  5. 现在,该字节在传递给int时隐式转换为printf

换句话说,就是这样:

0000 0000 0100 0000 0000 0000 0000 0000
          ^^^^^^^^^
          (char*)p+1
          vvvvvvvvv
          0100 0000 [0000 0000 0000 0000 0000 0000]
                     promotion to int when calling printf

因此,这就是为什么您看不到“ 8个随机位”的原因。


反之,如果您要做的是这样的话:

// notice the second cast to (int*) AFTER advancing 1 byte
printf("%d\n",*(int*)((char*)p + 1));

这将是未定义的行为。您可以看到一些随机位(这意味着更大的值),或者可能会因为运气而使零为零,但是由于它是UB,因此您无法真正期望任何有意义的东西。

,

我有512,在小尾数法中是: 0000 0000 0010 0000 0000 0000 0000 0000

正确,但实际上是0000 0000 00000010。字节序为 byte 字节,而不是半字节顺序。

p +1到0010

正确,它指向 byte 0000 0010。

当我打印2时是从0010开始的,但是使用%d时它应该不会打印0010 0000 ...

否,因为当取消引用8位char时,您会在8位临时对象中以值2结尾。

事实证明,诸如printf之类的可变参数函数都将小整数参数提升为int默认参数提升),而与格式说明符无关。因此,最后得到一个int,其值为2,然后printf打印该值。

,

您可能需要在打印字节之前对其进行复制

int main()
{
    const int x = 512;
    uint8_t * p = (uint8_t *)(&x);
    for (unsigned int i = 0u; i < sizeof(int); ++i)
    {
        const uint8_t value = *p++;
        printf("%d\n",value);
    }
    return 0;
}

将内存的副本制作为变量可防止编译器将位置方程解释为4字节整数(如您的示例)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。