【发布时间】: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 *)&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 之后的字节)肯定是未定义的行为