计算C中数据类型的范围

jsu*_*eld 5 c

我正在研究K&R第二版,并且无法弄清楚为什么我会得到一定的结果.我正在解决的问题是计算数据类型的上限和下限.特别:

"编写一个程序来确定char,short,int和long变量的范围,包括有符号和无符号,通过从标准头文件中打印适当的值并直接计算.如果你计算它们会更难:确定各种浮动的范围 - 点类型."

我已经了解了按位运算符和两个人的称赞,并且我认为应该对签名数据类型有效,但是它适用于对我没有任何意义的无符号数据类型.这是代码:

#include <stdio.h>

main()
{
    signed int i;

    i = ~0;
    i >>= 1;
    printf("Upper limit: %d\n", i);
    printf("Lower limit: %d\n", -i -1);
}
Run Code Online (Sandbox Code Playgroud)

这将导致-1被打印为上限,0被打印为下限.但是,如果我将i更改为unsigned int,我会得到我期望的结果(2147483647和-2147483648).我无法解决这个问题,因为我的理解是unsigned int永远不会小于0,而signed int应该使用这些按位运算符,即如果它是32位系统,

~0 == 11111111111111111111111111111111
Run Code Online (Sandbox Code Playgroud)

,和

~0 >> 1 == 011111111111111111111111111111111, 
           or 2147483647.
Run Code Online (Sandbox Code Playgroud)

知道我哪里错了吗?

tri*_*san 6

通过使用%d你对你的价值signed进行处理printf.

你可以%u改用.

添加

正如 Magn3s1um所指出的那样,你不需要指定signed,unsigned因为你的特定任务printf将为你完成所有工作.

  • @jsutterfield:如果您启用了所有警告(使用`gcc`),则会出现使用签名转换(%d)格式化未签名的警告,提醒您注意该问题. (2认同)

Gri*_*han 4

输出:

\n\n
    \n
  1. 注意:
    \n\xe2\x80\x9c 在表达式 中i >>= 1,负值右移。C 标准说这是一个实现定义的操作,许多实现将其定义为算术移位。在算术移位中,最高有效位保持不变(保持 MSB(有符号位)= 1)”。

    \n\n

    (您可以阅读:C 中的右移负数,这>>取决于编译器是否是有符号移位或无正弦移位,但可能在您的情况下它正在执行算术移位。)

    \n\n

    为此,在代码之后:

    \n\n
     i = ~0;  \n i >>= 1;\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    i依然~0。这是二进制 == 11111111111111111111111111111111

    \n\n

    因为~0==11111111111111111111111111111111是 == 2\'c 的补码1-1

    \n\n

    因此,当您使用格式字符串打印时,%d它会打印-1. 您应该使用%u打印最大无符号值 == ~0

    \n\n

    这里需要注意的是:

    \n\n
    \n

    \xc2\xa76.2.6.2 语言 45、\xc2\xa9ISO/IEC ISO/IEC 9899:201x

    \n\n

    (个\xe2\x80\x99 补码)。其中适用的是\n implementation-de\xef\xac\x81ned,即是否具有符号位1 和\n 所有值位为零(对于\xef\xac\x81 前两个)的值,或者具有符号位和\n 所有值\n 位1(对于\n\n) xe2\x80\x99 补码),是陷阱表示或正常\n 值。在符号和大小以及 1\xe2\x80\x99 补码的情况下,如果\n 此表示是正常值,则称为负零。

    \n
    \n\n

    您的理解是:

    \n\n

    ~0 >> 1 == 011111111111111111111111111111111是错的!(根据输出,它可能会在您的系统中发生,但不会发生)

    \n\n

    ~0 >> 1 == 111111111111111111111111111111111,注意 MSB(有符号位)是1

    \n\n

    对于无符号移位,请尝试以下操作:

    \n\n

    ~0U >> 1 == 011111111111111111111111111111111

    \n\n

    注意U未签名的后缀。

  2. \n
  3. 第二个 printf
    \n因为i-1,所以在第二个表达式-i - 1== - (-1) - 1== 1 - 1==中0,输出为零:0

  4. \n
\n