【问题标题】:How casting of char pointer to int pointer works?将 char 指针转换为 int 指针是如何工作的?
【发布时间】:2019-10-07 08:08:19
【问题描述】:

我正在学习 C。当我在那里查看指针时,我注意到一些我无法理解的奇怪行为。当将字符指针转换为整数指针时,整数指针包含一些奇怪的值,与 char 或 char ascii 代码没有合理的关系。但是在使用 '%c' 打印转换变量时,它会打印正确的 char 值。

使用 '%d' 打印会给出一些未知数字。

printf("%d", *pt); // prints as unknown integer value that too changes for every run

但是在打印为 '%c' 时

printf("%c", *pt); // prints correct casted char value

整个程序:

int main() {

char f = 'a';
int *pt = (int *)&f;

printf("%d\n", *pt);
printf("%c\n", *pt);

return 0;
}

请解释 char 到 int 指针转换的工作原理并解释输出值。

编辑:

如果我对程序进行以下更改,则输出将符合预期。也请解释一下。

#include <stdio.h>

int main() {

char f = 'a';
int *pt = (int *)&f;

printf("%d\n", *pt);
printf("%c\n", *pt);

int val = (int)f;
printf("%d\n", val);
printf("%c", val);
return 0;
}

输出:

97
a
97
a

请也解释一下这种行为。

【问题讨论】:

  • 假设一个 int 有 4 个字节。您设置了一个字节,其他三个是不确定的,访问它们是未定义的行为。
  • int *pt = (int *)&amp;f; 行调用了至少 3 种不同类型的未定义行为。换句话说,即使语言语法允许你这样做,你也不能这样做。这是some more information about undefined behavior。
  • %d 输出中的 4 个字节中的 1 个可能包含 'a' 和 0 的 ASCII 代码。其他 2 个字节未定义,然后读取可能会导致崩溃。或者编译器可以只打印 4 个笑脸,因为当调用未定义的行为时,你会得到编译器作者决定的任何东西。
  • @user3386109:人们可以这样做。 C 标准对“未定义行为”的定义是对其施加 no 要求的行为。它并不要求人们不要这样做。这很重要:C 标准未定义的某些行为由 C 实现定义。这些是 C 语言的扩展,C 标准明确邀请。 (将指向单个 char 的指针转换为指向 int 的指针不是这样的扩展;关键是 C 标准不禁止这样做,而不是说它是扩展。)
  • 通常将 char* 转换为 int* 然后使用该 int 指针可能会在每个强制 int 对齐的架构上中断,此代码可能没问题,因为堆栈将是 int 对齐的,但添加另一个char 变量可能会破坏它,重新定义指向未分配内存的指针(f 之后的字节)肯定是未定义的行为

标签: c pointers casting char


【解决方案1】:

对于 C 语言的规定,这只是普通的未定义行为。您有一个char 大小的内存区域,您正在从中读取int;结果未定义。

至于可能发生的情况:C 运行时最终在 main 执行之前将一些随机垃圾转储到堆栈上。 char f = 'a'; 碰巧将垃圾的一个字节重写为已知值,但对齐 pt 的填充意味着剩余的字节根本不会被重写,并且其中包含“无论运行时留下的任何内容”。因此,当您读取 int 时,在小端系统上,低字节等于 'a' 的值,但高字节是恰好留在填充空间中的任何垃圾。

至于为什么%c 起作用,因为低字节仍然是相同的,而%c 只检查提供的int 的低字节,所有的垃圾都被忽略了,事情就按预期工作了。不过,这只适用于小端机器;在大端机器上,它将是初始化为'a' 的高 字节,但低字节(垃圾)将由%c 打印。

【讨论】:

    【解决方案2】:

    您已将 f 定义为 char。这通常会在大多数硬件中分配 1 个字节的存储空间。您获取 f 的地址,将其转换为 (int *) 并将其分配给 int * 变量 pt。整数的大小取决于底层硬件 - 它可能是 2 或 4 甚至更多。当您将 f 的地址分配给 pt 时,分配给 pt 的地址取决于诸如 int 大小和对齐要求等因素。这就是为什么当您打印 *pt 时,您会看到一个垃圾值。实际上 'a' 的 ASCII 值包含在垃圾中,其位置取决于 int 大小、硬件的字节序等。如果打印 *pt 使用 %x,您将在输出中看到 61(十六进制的 61 是十进制的 97)。

    【讨论】:

      【解决方案3】:
      <#include <stdio.h>
      int main()
      {
      
          //type casting in pointers
      
          int a = 500; //value is assgned
          int *p;   //pointer p
          p = &a;   //stores the address in the pointer
          printf("p=%d\n*p=%d", p, *p);
          printf("\np+1=%d\n*(p+1)=%d", p + 1, *(p + 1));
      
          char *p0;
          p0 = (char *)p;
          printf("\n\np0=%d\n*p0=%d", p0, *p0);
      
          return 0;
      }
      

      【讨论】:

      • 一般来说,如果答案包含对代码的用途的解释,以及为什么在不介绍其他人的情况下解决问题的原因,答案会更有帮助。
      • @DCCoder 已经解释了该理论,因此代码对此进行了更多说明,并且询问 q 的人也对此有所帮助。
      猜你喜欢
      • 2017-02-12
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-10
      相关资源
      最近更新 更多