C中如何确定unsigned char的范围?

How can I confirm the range of unsigned char in C?

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

据我所知,unsigned char 的范围是从 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

我哪里做错了?

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

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

阅读例如this implicit conversion reference 获取更多信息。

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

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

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

您的代码调用了 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 :

[...] If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

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

The unsigned char for my compiler contains 1 byte.

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

So as per my knowledge the range of unsigned char is from 0 to 2^8 - 1 which is 255.

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

Now I want to confirm the max integer unsigned char can display is 255.

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

The following is my code:

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

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

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

未定义的行为:%d 需要类型为 int 的参数,它与类型为 size_tsizeof(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 调用具有潜在的未定义行为,因为您为预期字节分别为 unsigned longunsigned long long 和 [= 的参数传递了 int 值31=].

    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