C 打印存储在unsigned int中的实际负数
我有一个奇怪的问题。我有一个变量,它的实际值只有负值(这个变量只生成负整数)。但是在遗留代码中,我的一位老同事使用uint16而不是带符号的int来存储该变量的值。现在,如果我想打印该变量的实际负值,我该怎么做(我们使用什么格式说明符)?例如,如果实际值为-75,当我使用%d打印时,它会给我5位数的正值(我认为这是因为2的补码)。我想把它打印成75或-75 如果系统上的C 打印存储在unsigned int中的实际负数,c,C,我有一个奇怪的问题。我有一个变量,它的实际值只有负值(这个变量只生成负整数)。但是在遗留代码中,我的一位老同事使用uint16而不是带符号的int来存储该变量的值。现在,如果我想打印该变量的实际负值,我该怎么做(我们使用什么格式说明符)?例如,如果实际值为-75,当我使用%d打印时,它会给我5位数的正值(我认为这是因为2的补码)。我想把它打印成75或-75 如果系统上的int为32位,则打印16位int的正确格式为%hu表示无符号,而%hd表示有符号 检查以下各项的输出: uint16_t n
int
为32位,则打印16位int的正确格式为%hu
表示无符号,而%hd
表示有符号
检查以下各项的输出:
uint16_t n = (uint16_t)-75;
printf("%d\n", (int)n); // Output: 65461
printf("%hu\n", n); // Output: 65461
printf("%hd\n", n); // Output: -75
如果系统上的
int
为32位,则打印16位int的正确格式为%hu
表示未签名,而%hd
表示已签名
检查以下各项的输出:
uint16_t n = (uint16_t)-75;
printf("%d\n", (int)n); // Output: 65461
printf("%hu\n", n); // Output: 65461
printf("%hd\n", n); // Output: -75
假设您的朋友以某种方式正确地将有符号整数的位表示形式转换为无符号整数,那么将其提取回来的唯一符合标准的方法是使用并集作为-
typedef union {
uint16_t input;
int16_t output;
} aliaser;
现在,在您的代码中,您可以执行-
aliaser x;
x.input = foo;
printf("%d", x.output);
假设您的朋友以某种方式正确地将有符号整数的位表示形式转换为无符号整数,那么将其提取回来的唯一符合标准的方法是使用并集作为-
typedef union {
uint16_t input;
int16_t output;
} aliaser;
现在,在您的代码中,您可以执行-
aliaser x;
x.input = foo;
printf("%d", x.output);
正如另一个答案所解释的那样,继续与工会合作。我想说的是,如果您使用的是GCC,那么有一个非常酷的特性可以让您在不编写太多代码的情况下进行“按位”转换:
printf("%d", ((union {uint16_t in; int16_t out}) foo).out);
请参阅。按照另一个答案的解释,继续工会。我想说的是,如果您使用的是GCC,那么有一个非常酷的特性可以让您在不编写太多代码的情况下进行“按位”转换:
printf("%d", ((union {uint16_t in; int16_t out}) foo).out);
请参阅。#包括
uint16_t foo=-75;
printf(“==>%”PRId16“#包括
uint16_t foo=-75;
printf(“==>%”“PRId16”如果在名为x
的uint16\u t
中存储了16位负整数,则原始值可计算为x-65536
可以使用以下任意一种打印:
减去65536有效,因为:
- 根据C 2018 6.5.16.1 2,右操作数的值(负16位整数转换为赋值表达式的类型(本质上是左操作数的类型)
- 根据6.3.1.3.2,向无符号整数的转换通过“比新类型中可表示的最大值多出一个”的加或减操作。对于
uint16\u t
,比其最大值多出一个是65536
- 对于一个16位负整数,加65536一次将使其进入
uint16\u t
的范围
- 因此,减去65536将恢复原始值
脚注
根据int
是否为16位或更多,165536
将为long
或int
,因此这些语句小心地正确处理类型。第一个语句使用65536L
确保类型为long
。其余语句将值转换为int
。这是安全的,因为x-65536
的类型可以是long
,其值适合int
——除非您在限制int
为−32767到+32767,原始值可能为−32768,在这种情况下,您应该坚持使用第一个选项。如果在名为x
的uint16\u t
中存储了一个16位负整数,则原始值可以计算为x-65536
可以使用以下任意一种打印:
减去65536有效,因为:
- 根据C 2018 6.5.16.1 2,右操作数的值(负16位整数转换为赋值表达式的类型(本质上是左操作数的类型)
- 根据6.3.1.3.2,向无符号整数的转换通过“比新类型中可表示的最大值多出一个”的加或减操作。对于
uint16\u t
,比其最大值多出一个是65536
- 对于一个16位负整数,加65536一次将使其进入
uint16\u t
的范围
- 因此,减去65536将恢复原始值
脚注
根据int
是否为16位或更多,165536
将为long
或int
,因此这些语句小心地正确处理类型。第一个语句使用65536L
确保类型为long
。其余语句将值转换为int
。这是安全的,因为x-65536
的类型可以是long
,其值适合int
——除非您在限制int
为−32767到+32767,原始值可能为−32768,在这种情况下,您应该坚持第一个选项。如果u
是一个无符号整数类型的对象,并且将大小在u
类型范围内的负数存储到该对象中,则将-u
存储到u
类型的对象将保留该负数的大小。此behavior不取决于u
的表示方式。例如,如果u
和v
为16位无符号短
,但int
为32位,则将-60000存储到u
中将使其保持5536
[该实现的行为就像将65536添加到存储的值中,直到它在无符号短
]的范围内。计算-u
将得到-5536,将-5536存储到v
中将使其保持60000。如果u
是无符号整数类型的对象,则