使用 %u 读取签名的字符
Reading signed char using %u
#include <stdio.h>
int main() {
int i,n;
int a = 123456789;
void *v = &a;
unsigned char *c = (unsigned char*)v;
for(i=0;i< sizeof a;i++) {
printf("%u ",*(c+i));
}
char *cc = (char*)v;
printf("\n %d", *(cc+1));
char *ccc = (char*)v;
printf("\n %u \n", *(ccc+1));
}
此程序在我的 32 位 Ubuntu 机器上生成以下输出。
21 205 91 7
-51
4294967245
前两行输出我能看懂=>
- 第一行:字节在内存中的存储顺序。
- 第二行:第二个字节值的有符号值(2的补码)。
- 第3行:为什么这么大的值?
请解释最后一行输出。为什么要添加三个字节的 1
因为 (11111111111111111111111111001101) = 4294967245
。
-51
以 8 位十六进制存储为 0xCD
。 (假设2s补码二进制)
当您将它传递给 printf
之类的 variadic function 时,会进行默认参数提升,并且 char
会提升为 int
,表示形式为 0xFFFFFFCD
(对于 4 字节 int).
0xFFFFFFCD
解释为int
是-51
,解释为unsigned int
是4294967245
.
进一步阅读:Default argument promotions in C function calls
please explain the last line of output. WHY three bytes of 1's are
added
这个叫做sign extension. When a smaller signed number is assigned (converted) to larger number, its signed bit get's replicated to ensure it represents same number (for example in 1s and 2s compliment).
错误 printf
格式说明符
您正在尝试使用指定 unsigned [int]
的说明符 "%u"
打印 char
。与 printf
中的转换说明符不匹配的参数是 7.19.6.1 第 9 段中的未定义行为。
If a conversion specification is invalid, the behavior is undefined. If
any argument is not the correct type for the corresponding conversion
specification, the behavior is undefined.
使用char
存储有符号值
还要确保 char
包含 signed
值,显式使用 signed char
因为 char
可能表现为 signed char
或 unsigned char
。 (在后一种情况下,您的代码段的输出可能是 205 205
)。在 gcc
中,您可以使用 -funsigned-char
选项强制 char
表现得像 unsigned char
。
显然你的编译器使用带符号的字符,它是小端,二进制补码系统。
123456789d = 075BCD15h
Little endian: 15 CD 5B 07
因此 v+1 给出值 0xCD
。当它存储在带符号的字符中时,您会得到带符号的十进制格式的 -51
。
当传递给 printf 时,包含值 -51
的字符 *(ccc+1)
首先被隐式类型提升为 int
,因为像 printf 这样的可变参数函数有一条规则说明所有小整数参数将被提升为 int
( 默认参数提升 )。在此促销期间,标志被保留。您仍然有值 -51,但是对于 32 位有符号整数,这给出了值 0xFFFFFFCD
.
最后 %u
说明符告诉 printf 将其视为无符号整数,因此您最终得到 42.9 亿。
这里要理解的重要部分是%u
与实际的类型提升无关,它只是告诉printf如何在提升之后解释数据.
#include <stdio.h>
int main() {
int i,n;
int a = 123456789;
void *v = &a;
unsigned char *c = (unsigned char*)v;
for(i=0;i< sizeof a;i++) {
printf("%u ",*(c+i));
}
char *cc = (char*)v;
printf("\n %d", *(cc+1));
char *ccc = (char*)v;
printf("\n %u \n", *(ccc+1));
}
此程序在我的 32 位 Ubuntu 机器上生成以下输出。
21 205 91 7
-51
4294967245
前两行输出我能看懂=>
- 第一行:字节在内存中的存储顺序。
- 第二行:第二个字节值的有符号值(2的补码)。
- 第3行:为什么这么大的值?
请解释最后一行输出。为什么要添加三个字节的 1
因为 (11111111111111111111111111001101) = 4294967245
。
-51
以 8 位十六进制存储为 0xCD
。 (假设2s补码二进制)
当您将它传递给 printf
之类的 variadic function 时,会进行默认参数提升,并且 char
会提升为 int
,表示形式为 0xFFFFFFCD
(对于 4 字节 int).
0xFFFFFFCD
解释为int
是-51
,解释为unsigned int
是4294967245
.
进一步阅读:Default argument promotions in C function calls
please explain the last line of output. WHY three bytes of 1's are added
这个叫做sign extension. When a smaller signed number is assigned (converted) to larger number, its signed bit get's replicated to ensure it represents same number (for example in 1s and 2s compliment).
错误 printf
格式说明符
您正在尝试使用指定 unsigned [int]
的说明符 "%u"
打印 char
。与 printf
中的转换说明符不匹配的参数是 7.19.6.1 第 9 段中的未定义行为。
If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
使用char
存储有符号值
还要确保 char
包含 signed
值,显式使用 signed char
因为 char
可能表现为 signed char
或 unsigned char
。 (在后一种情况下,您的代码段的输出可能是 205 205
)。在 gcc
中,您可以使用 -funsigned-char
选项强制 char
表现得像 unsigned char
。
显然你的编译器使用带符号的字符,它是小端,二进制补码系统。
123456789d = 075BCD15h
Little endian: 15 CD 5B 07
因此 v+1 给出值 0xCD
。当它存储在带符号的字符中时,您会得到带符号的十进制格式的 -51
。
当传递给 printf 时,包含值 -51
的字符 *(ccc+1)
首先被隐式类型提升为 int
,因为像 printf 这样的可变参数函数有一条规则说明所有小整数参数将被提升为 int
( 默认参数提升 )。在此促销期间,标志被保留。您仍然有值 -51,但是对于 32 位有符号整数,这给出了值 0xFFFFFFCD
.
最后 %u
说明符告诉 printf 将其视为无符号整数,因此您最终得到 42.9 亿。
这里要理解的重要部分是%u
与实际的类型提升无关,它只是告诉printf如何在提升之后解释数据.