简体   繁体   English

打印存储在unsigned int内部的实际负数

[英]Printing the actual negative number stored inside unsigned int

I have a strange problem. 我有一个奇怪的问题。 I have a variable whose actual value is only negative(only negative integers are generated for this variable). 我有一个变量的实际值仅为负(此变量仅生成负整数)。 But in the legacy code, an old colleague of mine used uint16 instead of signed int to store the values of that variable. 但是在旧版代码中,我的一位老同事使用uint16而不是signed int来存储该变量的值。 Now if i wanted to print the actual negative value of that variable, how can i do that(what format specifier to us)? 现在,如果我想打印该变量的实际负值,我该怎么做(给我们什么格式的说明符)? For example if actual value is -75, when i print using %d its giving me 5 digit positive value(I think its because of two's complement). 例如,如果实际值为-75,则当我使用%d打印时,它给了我5位数的正值(我认为是因为有两个补码)。 I want to print it as 75 or -75. 我想将其打印为75或-75。

If an int is 32 bits on your system, then the correct format for printing a 16-bit int is %hu for unsigned and %hd for signed. 如果系统上的int是32位,则打印16位int的正确格式是%hu表示无符号)和%hd表示带符号)。

Examine the output of: 检查以下内容的输出:

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

Assuming your friend has somehow correctly put the bit representation for the signed integer into the unsigned integer, the only standard compliant way to extract it back would be to use a union as- 假设您的朋友以某种方式正确地将有符号整数的位表示形式放入无符号整数中,则将其提取回来的唯一符合标准的方法是使用联合作为-

typedef union {
    uint16_t input;
    int16_t output;
} aliaser;

Now, in your code you can do - 现在,在您的代码中,您可以-

aliaser x;
x.input = foo;
printf("%d", x.output);
#include <inttypes.h>

uint16_t foo = -75;
printf("==> %" PRId16 " <==\n", foo); // type mismatch, undefined behavior

If a 16-bit negative integer was stored in a uint16_t called x , then the original value may be calculated as x-65536 . 如果将16位负整数存储在称为xuint16_t ,则原始值可以计算为x-65536

This can be printed with any of 1 : 这可以印有任何的1:

printf("%ld", x-65536L);

printf("%d", (int) (x-65536));

int y = x-65536;
printf("%d", y);

Subtracting 65536 works because: 减去65536的原因是:

  • Per C 2018 6.5.16.1 2, the value of the right operand (a negative 16-bit integer is converted to the type of the assignment expression (which is essentially the type of the left operand). 根据C 2018 6.5.16.1 2,右操作数的值(一个16位负整数被转换为赋值表达式的类型(本质上是左操作数的类型)。
  • Per 6.3.1.3 2, the conversion to an unsigned integer operates by adding or subtracting “one more than the maximum value that can be represented in the new type”. 根据6.3.1.3 2,向无符号整数的转换通过加或减“比新类型可以表示的最大值多一个”来进行。 For uint16_t , one more than its maximum is 65536. 对于uint16_t ,比最大值uint16_t多一个。
  • With a 16-bit negative integer, adding 65536 once brings it into the range of a uint16_t . 对于16位负整数,将65536加一次会使它进入uint16_t的范围。
  • Therefore, subtracting 65536 restores the original value. 因此,减去65536将恢复原始值。

Footnote 脚注

1 65536 will be long or int according to whether int is 16 bits or more, so these statements are careful to handle the type correctly. 1 65536根据int是16位还是更多位而为longint ,因此这些语句要小心处理正确的类型。 The first uses 65536L to ensure the type is long . 第一种使用65536L以确保类型long The rest convert the value to int . 其余的将值转换为int This is safe because, although the type of x-65536 could be long , its value fits in an int —unless you are executing in a C implementation that limits int to −32767 to +32767, and the original value may be −32768, in which case you should stick to the first option. 这是安全的,因为尽管x-65536的类型可能很long ,但其值适合int除非您正在将int限制为-32767到+32767的C实现中执行,并且原始值可能是-32768,在这种情况下,您应该坚持第一个选择。

Go ahead with the union, as explained by another answer. 如另一个答案所述,继续进行工会。 Just wanted to say that if you are using GCC, there's a very cool feature that allows you to do that sort of "bitwise" casting without writing much code: 只是想说,如果您使用的是GCC,则有一个非常酷的功能,使您无需编写太多代码即可进行这种“按位”转换:

printf("%d", ((union {uint16_t in; int16_t out}) foo).out);

See https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Cast-to-Union.html . 参见https://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Cast-to-Union.html

If u is an object of unsigned integer type and a negative number whose magnitude is within range of u 's type is stored into it, storing -u to an object of u 's type will leave it holding the magnitude of that negative number. 如果u是无符号整数类型的对象,并且将大小在u类型范围内的负数存储在其中,则将-u存储到u类型的对象将使其保持该负数的大小。 This behavior does not depend upon how u is represented. 此行为不取决于u的表示方式。 For example, if u and v are 16-bit unsigned short , but int is 32 bits, then storing -60000 into u will leave it holding 5536 [the implementation will behave as though it adds 65536 to the value stored until it's within range of unsigned short ]. 例如,如果uv是16位unsigned short ,但int是32位,则将-60000存储到u中将使它保持5536 [实现的行为就像将65536添加到存储的值中,直到它在unsigned short ]。 Evaluating -u will yield -5536, and storing -5536 into v will leave it holding 60000. 计算-u将产生-5536,将-5536存储到v中将保留60000。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM