我有一个奇怪的问题。我有一个变量的实际值仅为负(此变量仅生成负整数)。但是在旧版代码中,我的一位老同事使用uint16而不是signed int来存储该变量的值。现在,如果我想打印该变量的实际负值,我该怎么做(给我们什么格式的说明符)?例如,如果实际值为-75,则当我使用%d打印时,它给了我5位数的正值(我认为是因为有两个补码)。我想将其打印为75或-75。
答案 0 :(得分:1)
如果您系统上的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
答案 1 :(得分:1)
假设您的朋友以某种方式正确地将有符号整数的位表示形式放入无符号整数中,则将其提取回来的唯一符合标准的方法是使用并集as-
typedef union {
uint16_t input;
int16_t output;
} aliaser;
现在,您可以在代码中进行操作-
aliaser x;
x.input = foo;
printf("%d", x.output);
答案 2 :(得分:1)
#include <inttypes.h>
uint16_t foo = -75;
printf("==> %" PRId16 " <==\n", foo); // type mismatch, undefined behavior
答案 3 :(得分:1)
如果将16位负整数存储在名为uint16_t
的{{1}}中,则原始值可以计算为x
。
可以用 1 中的任何一个打印:
x-65536
减去65536之所以有效,是因为:
printf("%ld", x-65536L);
printf("%d", (int) (x-65536));
int y = x-65536;
printf("%d", y);
,其最大值为65536。uint16_t
的范围。 1 uint16_t
是65536
是16位还是更多,long
将是int
或int
,因此这些语句要小心处理类型正确。第一个使用65536L
来确保类型为long
。其余的将值转换为int
。这是安全的,因为尽管x-65536
的类型可以为long
,但其值适合int
-除非您正在将int
限制为-的C实现中执行- 32767到+32767,原始值可能是-32768,在这种情况下,您应该坚持使用第一个选项。
答案 4 :(得分:0)
继续工会,如另一个答案所述。只是想说,如果您使用的是GCC,则有一个非常酷的功能,使您无需编写太多代码即可进行这种“按位”转换:
printf("%d", ((union {uint16_t in; int16_t out}) foo).out);
请参见https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Cast-to-Union.html。
答案 5 :(得分:0)
如果u
是无符号整数类型的对象,并且将大小在u
类型范围内的负数存储在其中,则将-u
存储到{ {1}}的类型将保留该负数的大小。此行为不依赖于u
的表示方式。例如,如果u
和u
是16位v
,但是unsigned short
是32位,则将-60000存储到int
中将使其保持{ {1}} [该实现的行为就像是将65536添加到存储的值中,直到它位于u
的范围内为止]。评估5536
将产生-5536,并将-5536存储到unsigned short
中将使其保持60000。