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

相同的地址,在 c 中通过 void 指针类型转换不同的值

如何解决相同的地址,在 c 中通过 void 指针类型转换不同的值

#include <stdio.h>

int  main() {
  double p = 10.3;
  void *j =  &p;
  *((int*) j) = 2;

  printf("%i: %p\n",*((int *)j),&p);
  printf("%i: %p\n",(int)p,&p);

  return 0;
}

很明显,我认为这就是发生的事情,而且我确定我是不对的: 假设一个 double 是 8 个字节,一个 int 是 4 个字节。
当我将 j 强制转换为 int* 并通过指针取消引用为其分配值 2 时,赋值的左侧基本上将 j 的前四个字节分配了值 2 . 现在在第一个 printf 语句中,它按预期工作,前四个字节等于值 2。但是在第二个 printf 语句中,当我将 p 转换为 int 时,为什么不打印 2?我不是通过 void 指针覆盖了 p 的前四个字节并为它们分配了值 2 吗?

那么这里到底发生了什么?正确理解它所需的适当框架是什么?

解决方法

该程序通过违反严格的别名规则(double 对象通过不兼容类型 int 的表达式写入)导致未定义的行为。

所以程序的行为不受语言规则的约束。如需进一步阅读,请参阅 Undefined,unspecified and implementation-defined behavior

,

那么这里到底发生了什么?

既然这是 UB,你在 C 标准中找不到答案,因此你在查看 C 代码时如何期望找到答案?显然,C 代码不会告诉你太多。您需要查看程序集输出,而您的问题中缺少这一点,使其不完整。这可能解释了被否决的原因:您没有提供足够的信息。

但你不需要问我们:去godbolt,选择你的编译器,查看程序集输出,添加一个执行器,还查看运行程序的结果,这样你就可以将输出与生成的程序集相关联。确保选择与您用来获得原始行为的编译器版本和平台相同的编译器版本和平台 - 不要忘记编译器的优化级别参数(又名编译器标志),即。如果编译时使用了 -Osomething 标志,则需要将相同的标志传递给 Godbolt 上的编译器和执行器。

一旦您获得程序集输出 - 通过向计算机上的编译器提供 -s 标志,或通过从 Godbolt 复制它,您可以将其添加到问题中,做一些工作来弄清楚什么是继续,并添加您得到的真正问题 - 与程序集相关 - 如果您将无法看到程序集代码如何生成您看到的输出。

但是不要问为什么编译器会生成这样的汇编代码:UB 意味着允许生成这样的汇编代码 :) UB 在某些方面是全权委托:编译器不应该是恶意的,但它不需要对它“很好”,因此生成的代码可能非常不直观。

,

正如其他同事所说,它是 UB。 但是从中抽象出来的 floatint 具有不同的二进制表示。所以"2.0f"会比"2"存储在内存中。您可以使用一个非常简单的程序来检查它:

#include <stdio.h>
#include <string.h>

float x = 2.0f;
int y = 2;
unsigned char bytes[sizeof(x)];


int main(void)
{

    if(sizeof(y) == sizeof(x))
    {
        memcpy(bytes,&x,sizeof(bytes));

        printf("float %f is in binary: ",x);
        for(size_t i = 0; i < sizeof(bytes); i++)
        {
            printf("%hhx ",bytes[i]);
        }

        
        memcpy(bytes,&y,sizeof(bytes));

        printf("\n\nint %d is in binary: ",y);
        for(size_t i = 0; i < sizeof(bytes); i++)
        {
            printf("%hhx ",bytes[i]);
        }

        memcpy(&x,sizeof(x));

        printf("\n\nfloat %f after integer representation of integer 2 copy\n",x);
    }

}

结果:

x86-64 gcc 10.2

Program returned: 0
Program stdout

float 2.000000 is in binary: 0 0 0 40 

int 2 is in binary: 2 0 0 0 

float 0.000000 after integer representation of integer 2 copy

在这个程序中,memcpy(&x,sizeof(x)); 的作用与您的指针赋值完全相同,但以正确的方式进行。

编辑:这里也是双版本https://godbolt.org/z/fxccjf

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