【问题标题】:How can I confirm the range of unsigned char in C?如何确认 C 中无符号字符的范围?
【发布时间】:2018-12-16 19:01:38
【问题描述】:

我的编译器的无符号字符包含 1 个字节。

据我所知,无符号字符的范围是从 0 到 2^8 - 1,即 255。

现在我想确认 unsigned char 可以显示的最大整数是 255。

以下是我的代码:

#include <stdio.h>
#include <limits.h>
int main(void)
{
    printf("unsigned char has %d bytes.\n", sizeof(unsigned char));

    unsigned char a;

    a = 0;

    printf("%d\n", a - 1); 
    printf("%u\n", a - 1); 
    printf("%lu\n", a - 1); 
    printf("%llu\n", a - 1);   
    printf("%zu\n", a - 1); 

    return 0;
}

输出是

unsigned char has 1 bytes.
-1
4294967295
4294967295
4294967295 
4294967295

4294967295 是 2^32 - 1

我哪里做错了?

【问题讨论】:

标签: c char integer range unsigned


【解决方案1】:

首先,当您将小于int 的整数参数传递给可变参数函数(如printf)时,它会自动提升为int

其次,当您使用算术时,较小的整数类型再次被提升为int

阅读例如this implicit conversion reference 了解更多信息。

如果您想打印char(或者更确切地说是unsigned char)值,您需要使用hh 前缀作为格式说明符(参见例如this printf and family reference):

printf("%hhu\n", (unsigned char) (a - 1));

【讨论】:

  • 完全不需要hh 长度修饰符。正如您所说的那样,(unsigned char)(a - 1) 在传递给printf 时会提升为int,具有相同的值。 %u 可以,%d 也可以,除了 sizeof(unsigned char) == sizeof(int) 的罕见架构。
  • 相反,如果您坚持使用hh 长度修饰符,则可以使用更简单的方法:printf("%hhu\n", -1);
【解决方案2】:
a-1

这是算术运算,会进行隐式转换。编译器会将其视为整数。尝试将 -1 分配给无符号类型,然后检查该值。您还应该注意 printf 操作数,例如 %d,对于该特定示例,它需要整数。

【讨论】:

    【解决方案3】:

    你的知识在微妙的方面是不完整的:

    我的编译器的 unsigned char 包含 1 个字节。

    类型unsigned char根据定义对于所有编译器来说正好是一个字节。

    据我所知,无符号字符的范围是从 0 到 2^8 - 1,即 255

    不完全是:unsigned char最小 值位数是 8,并且此类型不允许填充位,这意味着 最小 大小byte 是 8 位。事实上,现在大多数架构都标准化为 8 位字节,但 C 标准允许其他更大的位宽,并且一些微控制器使用 16 位字节(甚至 32 位字节)。在此类处理器上,unsigned char 为 16 位(甚至 32 位)。

    现在我想确认unsigned char可以显示的最大整数是255

    这是一个真正的问题,可以在编译时和运行时验证。

    以下是我的代码:

    #include <stdio.h>
    #include <limits.h>
    

    包含&lt;limits.h&gt; 是一个好方法:UCHAR_MAX 是您想要打印甚至直接在预处理指令中测试的值。

    int main(void) {
        printf("unsigned char has %d bytes.\n", sizeof(unsigned char));
    

    未定义的行为:%d 需要 int 类型的参数,这与 size_t 类型的 sizeof(unsigned char) 不同并且可能不兼容。使用%zu 或将参数转换为(int)sizeof(unsigned char)。但请注意,sizeof(unsigned char) 根据定义 始终计算为 1,类型为 size_t

        unsigned char a;
        a = 0;
        printf("%d\n", a - 1);
    

    a - 1 的计算结果始终为 -1,因为 a 被提升为 int 并且 0 - 1 的值为 -1。你想打印(unsigned char)(a - 1),或者只是(unsigned char)-1

        printf("%u\n", a - 1);
    

    这将打印(unsigned int)-1 的值,即UINT_MAX,而不是UCHAR_MAX

        printf("%lu\n", a - 1); 
        printf("%llu\n", a - 1);   
        printf("%zu\n", a - 1); 
    

    上面的 3 个 printf 调用具有潜在的未定义行为,因为您为一个参数传递了一个 int 值,该参数的预期字节分别为 unsigned longunsigned long longsize_t

        return 0;
    }
    

    这是一个更简单的方法:

    #include <stdio.h>
    #include <limits.h>
    
    int main() {
        printf("UCHAR_MAX = %u\n", UCHAR_MAX);
        printf("(unsigned char)-1 = %u\n", (unsigned char)-1);
        printf("-1 with %%hhu conversion: %hhu\n", -1);
        return 0;
    }
    

    输出:

    UCHAR_MAX = 255
    (unsigned char)-1 = 255
    -1 with %hhu conversion: 255
    

    【讨论】:

      【解决方案4】:

      您的代码调用了undefined behaviour,因为您使用了错误的 printf 格式说明符。

      GCC 编译器警告:

      prog.c: In function 'main':
      prog.c:5:32: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=]
           printf("unsigned char has %d bytes.\n", sizeof(unsigned char));
                                     ~^            ~~~~~~~~~~~~~~~~~~~~~
                                     %ld
      prog.c:13:15: warning: format '%lu' expects argument of type 'long unsigned int', but argument 2 has type 'int' [-Wformat=]
           printf("%lu\n", a - 1);
                   ~~^     ~~~~~
                   %u
      prog.c:14:16: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 2 has type 'int' [-Wformat=]
           printf("%llu\n", a - 1);
                   ~~~^     ~~~~~
                   %u
      prog.c:15:15: warning: format '%zu' expects argument of type 'size_t', but argument 2 has type 'int' [-Wformat=]
           printf("%zu\n", a - 1);
                   ~~^     ~~~~~
                   %u
      

      C11 $7.19.6.1 p9:

      [...] 如果任何参数不是对应的正确类型 转换规范,行为未定义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-06
        • 2011-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-07
        • 1970-01-01
        相关资源
        最近更新 更多