在 C 中取消引用指针时出现意外值

问题描述 投票:0回答:1

以下代码

#include <stdio.h>

int main()
{
    long long data = 0xFFFEABCD11112345;

    char *pData = (char *)&data;
    printf("Value at address %p is %x\n", pData, *pData);

    pData = pData + 5;
    printf("Value at address %p is %x\n", pData, *pData);

    return 0;
}

产生类似于

的输出
Value at address 00000023515FFC00 is 45
Value at address 00000023515FFC05 is ffffffab

鉴于

pData
char *
,我预计第二个值是
ab
而不是
ffffffab
。我相信
%x
格式说明符可能是罪魁祸首,但我并不完全理解它。领先的
f
来自哪里?

c pointers pointer-arithmetic format-specifiers
1个回答
0
投票

char
可以是有符号的也可以是无符号的,具体取决于编译器。 char 默认是有符号的还是无符号的? 在本例中它似乎是有符号的。

在主流计算机上,有符号

char
只能保存值 -128 到 127。
0xAB
在这样的计算机上将是十进制负数 2 的补码表示
-85

C 有各种形式的隐式类型提升,当在大多数表达式中使用像

char
这样的小类型时,或者在本例中,当传递给可变参数函数
printf
时,就会发生这种情况。可变参数函数的特殊隐式提升规则集称为“默认参数提升”,它们规定小整数类型会提升为
int
,无论符号性如何。

如果我们有一个带符号的

char
,其值为-85,那么在升级到
int
期间,该符号受到尊重,这称为符号扩展。这意味着该值仍然是 -85,但升级后的
int
的二进制 2 补码表示可能是
0xFFFFFFAB
(假设为 32 位 int)。

但是,如果我们有无符号

char
,其值为 0xAB/171,则在升级到
int
期间,该值将被保留,并且不存在任何符号。所以我们可以通过转换来避免符号扩展:
(unsigned char)*pData
。从有符号到无符号的显式转换是明确定义的。

printf
的格式字符串与此促销活动无关。
%x
需要一个
unsigned int
的参数,因此我们实际上是在撒谎打印,因为我们传递了
char
提升为
int
,严格来说是未定义的行为。然而,在这种情况下,
printf
只是读取
int
的二进制表示并将其呈现为
0xFFFFFFAB

© www.soinside.com 2019 - 2024. All rights reserved.