使用指针进行类型转换

时间:2015-01-24 21:35:26

标签: c

我正在根据下面的输出寻找一些解释,我明白有一种类型转换..但是在为double \ int数据类型赋值时会发生什么?哪些位填充?指针指向哪些位?

#include <stdio.h>

int main() {
    double d = 2;

    double *pd = &d;
    int *pi = (int *) &d;

    printf("pi = %p, pd = %p, *pd = %f, *pi = %f\n", pi, pd, *pd,  (double) *pi);

    return 0;
}

输出:

pi = 0x7fff5504ba70, pd = 0x7fff5504ba70, *pd = 2.000000, *pi = 0.000000

4 个答案:

答案 0 :(得分:1)

double *pd = &d;
int *pi = (int *) &d;

无法保证_Alignof(double)>=_Alignof(int)d恰好恰好对齐。如果不是,则表示您有未定义的行为。

printf("pi = %p, pd = %p, *pd = %f, *pi = %f\n", pi, pd, *pd,  (double) *pi);

现在printf - 召唤是一个坏人:

  • 第一个参数应该是void*,但实际上是int*。 UB。
  • 第二个参数应为void*,但实际上是double*。 UB再次。
  • *pi违反了别名。 UB又来了。

在实践中,现代系统上的事情几乎不可怕。只有最后一个可能在那里有危险,但两者都没有定义。


您所看到的内容可以很容易地解释,假设上面没有任何UB做任何事情&#34;令人惊讶&#34; (这可能是令人惊讶的),初始化程序实际上是2而不是4 还假设int为32位且doubleIEEE double-precision floating-point-format,保存为little-endian:

bits
63    Sign-bit 0 (positive)
62-52 Biased Exponent (1023+1 == 1024 == 100_0000_0000<sub>2</sub>
51-0  Mantissa (All zeroes, the implicit 1 before the decimal-point is not saved, ever)

因此,低阶32位为零,通过将它们解释为int来获取。

答案 1 :(得分:0)

pi = 0x7fff5504ba70:这是d

的内容

pd = 0x7fff5504ba70:无论指针类型如何,它都是d的地址

* pd = 2.000000:应该是4.000000。这是一个错字吗? (编辑 - 你纠正了你的问题所以现在这是正确的)

* pi = 0.000000:它是0x7fff5504ba70处的位的值被解释为整数(因为pi是指向int的指针),然后转换为double(因为你已经转换为double)。在我的机器上,4为双倍是0x4010000000000000。所以前4个字节都是0(因为在我的机器上,cpu是little-endian,double是8个字节,int是4个字节)。

发生的事情是pi指向与pd相同的地址,但是当你取消引用pi时只考虑4个第一个字节,这4个字节都是0。

答案 2 :(得分:0)

你骗了编译器。

您将pi指向d的地址。这不会改变pi指向仍具有double的类型和位表示的对象的事实。

当您访问(double)*pi时,您的程序会尝试解释双精度的,就好像它是int一样。结果(通常)是一个无意义的值,然后转换为double

如果指针未正确对齐以访问int,它甚至可能会导致程序崩溃。

答案 3 :(得分:0)

只要您尝试将一种类型的内部表示(此处为double)解释为另一种类型的内部表示(此处为int),您将获得未定义的行为:任何版本的C规范都不会涵盖此内容。

换句话说,它依赖于编译器和体系结构。许多现代架构使用IEEE 754作为浮点数,即尾数(或sigificand)部分和指数部分,全部在基数2中。

Name        Common name        Base     Significand     E min   E max   Decimal Decimal
                                        digits                          digits  E max
binary32    Single precision    2       24              −126    +127    7.22    38.23
binary64    Double precision    2       53              −1022   +1023   15.95   307.95

但是没有什么能够迫使某个特定的架构使用这样的表示,所以你需要将代码引导到UB,除非你把它记录下来以适应一个特定的系统。

参考文献:

相关问题