C语言 为什么我必须使用结构解引用操作符而不是仅仅强制转换一个联合

jvidinwx  于 2023-01-25  发布在  其他
关注(0)|答案(2)|浏览(115)

为什么下面两个对f的调用给出不同的输出?

#include"stdio.h"

typedef union {
  int value_int;
  char value_char;
} my_union_t;

void f(int x)
{
  printf("x: %d\n", x);
}

void main()
{
  my_union_t u;
  u.value_int = 7;
  my_union_t * p_u = &u;
  f( (int) p_u );
  f( p_u->value_int );
}

输出:

x: -393095784
x: 7
vxf3dgd4

vxf3dgd41#

(int) p_u取一个指针指向一个并集,该指针是一个地址,并将其转换为int。您的输出看起来与我预期的完全一样。-393095784是某个指针(RAM内存中的变量地址)的有符号整数表示。
p_u->value_int从联合体中读取value_int,看起来和我预期的完全一样。还要知道p_u->value_int完全等价于(*p_u).value_int*被称为"解引用操作符"。它读取指针的"内容",或者换句话说,获取指针所指向的地址中存储的内容。*p_u表示"读取p_u指针所指向的内容",其内容是并集本身。some_ptr->(*some_ptr).的简写。
请注意,当您将指针地址强制转换为int时,指针地址会从无符号值溢出到有符号值。如果您没有将其强制转换为int,它将如下所示:

Address, assuming your hardware has 64-bit addresses
AND the address didn't roll over more than once when
you originally cast it into an `int` type:
18446744073316455832
0xFFFFFFFFE891D598

Address, assuming your hardware has 32-bit addresses
AND the address didn't roll over more than once when
you originally cast it into an `int` type:
3901871512
0xE891D598

Address, **using the exact pointer size for the hardware
this code is actually being run on!**:
0xffffffffe891d598

sizeof(pointer) on this hardware architecture =
sizeof(void*) = 8 bytes = 64 bits.

如上图所示,64位地址打印输出(第1块)和"精确指针大小"打印输出(第三块)是相同的地址。这意味着我运行程序的硬件架构使用64位指针。这也可以通过打印sizeof(void*)来获得任何指针的大小,* 注意这里使用void*只是为了方便。实际上,您可以在那里使用任何指针类型或实际的指针变量,因为在给定的硬件架构上,所有指针类型的指针大小都相同。*
上面的输出是由这个程序产生的,你可以在这里实时运行:https://onlinegdb.com/r1YSjZt4_

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>

int main()
{
    printf("\nAddress, assuming your hardware has 64-bit addresses\n"
           "AND the address didn't roll over more than once when\n"
           "you originally cast it into an `int` type:\n");
    printf("%" PRIu64 "\n", (uint64_t)-393095784);
    printf("0x%" PRIX64 "\n", (uint64_t)-393095784);
    
    printf("\nAddress, assuming your hardware has 32-bit addresses\n"
           "AND the address didn't roll over more than once when\n"
           "you originally cast it into an `int` type:\n");
    printf("%" PRIu32 "\n", (uint32_t)-393095784);
    printf("0x%" PRIX32 "\n", (uint32_t)-393095784);
    
    printf("\nAddress, **using the exact pointer size for the hardware\n"
           "this code is actually being run on!**:\n");
    printf("%p\n", (void *)-393095784);
    
    printf("\nsizeof(pointer) on this hardware architecture =\n"
           "sizeof(void*) = %zu bytes = %zu bits.\n", 
            sizeof(void*), sizeof(void*)*8);
    
    return 0;
}

另请参阅您问题下方的评论。

参考文献:

  1. http://www.cplusplus.com/reference/cstdio/printf/https://en.cppreference.com/w/cpp/io/c/fprintf
  2. http://www.cplusplus.com/reference/cstdint/
  3. http://www.cplusplus.com/reference/cinttypes/
t2a7ltrp

t2a7ltrp2#

正如另一个答案所指出的,您不希望将指针强制转换为int型。您需要解引用。
编译器不允许这样做:
f((int) u);
但是,您可以获取地址,强制转换为整数指针,然后解引用:
f(*(int *) &u)
确实是u.value_int == *(int *) &u
这似乎是您所能得到的最接近于“将联合强制转换为整数”的方法。

相关问题