计算C中变量类型的范围

Calculate range of variable types in C

这里是业余爱好者,很抱歉提出了这个问题。 K&R 前。 2-1.使用头常量and/or直接计算,计算范围为各种变量类型(char、short、int、long)+浮点类型。我用limits.h常量打印定宽变量类型的范围,供参考。而且我还得查IEEE754.

我的 max 函数为我想要的结果少了 1,比如:0xfe、0xfffe 等,所以 LSB 出于某种原因没有切换到 1。这是为什么?昨天,在思考这个问题时,我想到了使用 void* 类型将各种变量类型传递给 min-max 函数的想法。为了能够取消引用 void* 类型存储具有不同长度的固定宽度数字的地址,我想到了将其简单地转换为 size_t* 类型,并且以某种方式起作用,但我不知道为什么。这是否合法,我从未在我的 C 编程书籍中看到过。如果它不合法,还有哪些其他可能性可以取消引用 void* 类型?

我不想使用循环和检查溢出,那个方法很慢。


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

void unsigned_max(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;

    while(bit) {
        *(size_t*)data_ptr |= 1 << bit;
        bit--;
    }
}

void unsigned_min(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;

    while(bit){
        *(size_t*)data_ptr &= 0 << bit;
        bit--;
    }
}

void signed_min(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;
    *(size_t*)data_ptr |= 1 << bit;
    bit--;

    while (bit) {
        *(size_t*)data_ptr |= 0 << bit;
        bit--;
    }
}

void signed_max(void* data_ptr, size_t data_size) {
    int bit = ((int)data_size * 8) - 1;
    *(size_t*)data_ptr &= 0 << bit;
    bit--;

    while (bit) {
        *(size_t*)data_ptr |= 1 << bit;
        bit--;
    }
}

int main(void) {

    unsigned char u_byte = 0;
    char byte = 0;
    unsigned short ushort_intgr = 0;
    short short_intgr = 0;
    unsigned int u_intgr = 0;
    int intgr = 0;
    unsigned long ulong_intgr = 0;
    long long_intgr = 0;

    char str_output[18] = "Min-max range of";
    char delimiter[18] =  "================";

    /*
     * Print ranges of unsigned and signed instances of char, short, int and long
     * variables using limits.h constants.
     */
    
    printf("%s unsigned char:\n%x,%x\n", str_output, u_byte, UCHAR_MAX);
    printf("%s signed char:\n%x,%x\n", str_output, CHAR_MIN, CHAR_MAX);
    printf("%s unsigned short:\n%x,%x\n", str_output, ushort_intgr, USHRT_MAX);
    printf("%s signed short:\n%x,%x\n", str_output, SHRT_MIN, SHRT_MAX);
    printf("%s unsigned int:\n%x,%x\n", str_output, u_intgr, UINT_MAX);
    printf("%s signed int:\n%x,%x\n", str_output, INT_MIN, INT_MAX);
    printf("%s unsigned long:\n%x,%x\n", str_output, ulong_intgr, ULONG_MAX);
    printf("%s signed long:\n%x,%x\n", str_output, LONG_MIN, LONG_MAX);
    
    
    printf("%s\n", delimiter);

    /*
     * Print ranges of unsigned and signed instances of char, short, int and long
     * variables using bitwise operations.
     */

    printf("%s unsigned char:\n%d,", str_output, u_byte);
    unsigned_max(&u_byte, sizeof(u_byte));
    printf("%x\n", u_byte);

    printf("%s signed char:\n", str_output);
    signed_min(&u_byte, sizeof(u_byte));
    printf("%x,", u_byte);
    signed_max(&u_byte, sizeof(u_byte));
    printf("%x\n", u_byte);

    printf("%s unsigned short:\n%d,", str_output, ushort_intgr);
    unsigned_max(&ushort_intgr, sizeof(ushort_intgr));
    printf("%x\n", ushort_intgr);

    printf("%s signed short:\n", str_output);
    signed_min(&short_intgr, sizeof(short_intgr));
    printf("%x,", short_intgr);
    signed_max(&short_intgr, sizeof(short_intgr));
    printf("%x\n", short_intgr);

    printf("%s unsigned int:\n%u,", str_output, u_intgr);
    unsigned_max(&u_intgr, sizeof(u_intgr));
    printf("%x\n", u_intgr);

    printf("%s signed int:\n", str_output);
    signed_min(&intgr, sizeof(intgr));
    printf("%x,", intgr);
    signed_max(&intgr, sizeof(intgr));
    printf("%x\n", intgr);

    printf("%s unsigned long:\n%lu,", str_output, ulong_intgr);
    unsigned_max(&ulong_intgr, sizeof(ulong_intgr));
    printf("%x\n", ulong_intgr);

    printf("%s signed long:\n", str_output);
    signed_min(&long_intgr, sizeof(long_intgr));
    printf("%x,", long_intgr);
    signed_max(&long_intgr, sizeof(long_intgr));
    printf("%x\n", long_intgr);

    return 0;
}

我的输出是:

Min-max range of unsigned char:
0,ff
Min-max range of signed char:
ffffff80,7f
Min-max range of unsigned short:
0,ffff
Min-max range of signed short:
ffff8000,7fff
Min-max range of unsigned int:
0,ffffffff
Min-max range of signed int:
80000000,7fffffff
Min-max range of unsigned long:
0,ffffffff
Min-max range of signed long:
80000000,7fffffff
================
Min-max range of unsigned char:
0,fe
Min-max range of signed char:
fe,7e
Min-max range of unsigned short:
0,fffe
Min-max range of signed short:
ffff8000,7ffe
Min-max range of unsigned int:
0,fffffffe
Min-max range of signed int:
80000000,7ffffffe
Min-max range of unsigned long:
0,fffffffe
Min-max range of signed long:
80000000,7ffffffe

我也看了K&R解法一书,作者通常都是用优雅的一行来解决所有问题。当我 运行 它时它似乎不起作用,为最小值和最大值返回零。我知道 -0 是补码形式的每一位都是真的。那个时间-0 可以存储为 0x1111 吗?所以 0x1111 >> 1 = 0x0111; 0x0111*(-1) = 0x1000?

printf("signed char min = %d\n", -(char)((unsigned char) -0 >> 1));
printf("signed char max = %d\n", (char)((unsigned char) -0 >> 1));
printf("unsigned char max = %u\n", (unsigned char) -0);
...

在二进制补码机上,您需要

printf("signed char min:        %hhd\n", -(signed char)((unsigned char)~0 >> 1) - 1);
printf("signed char max:        %hhd\n", (signed char)((unsigned char)~0 >> 1));
printf("unsigned char max:      %hhu\n", (unsigned char)~0);

printf("signed short min:       %hd\n", -(signed short)((unsigned short)~0 >> 1) - 1);
printf("signed short max:       %hd\n", (signed short)((unsigned short)~0 >> 1));
printf("unsigned short max:     %hu\n", (unsigned short)~0);

printf("signed int min:         %d\n", -(signed int)(~0U >> 1) - 1);
printf("signed int max:         %d\n", (signed int)(~0U >> 1));
printf("unsigned int max:       %u\n", ~0U);

printf("signed long min:        %ld\n", -(signed long)(~0UL >> 1) - 1);
printf("signed long max:        %ld\n", (signed long)(~0UL >> 1));
printf("unsigned long max:      %lu\n", ~0UL);

printf("signed long long min:   %lld\n", -(signed long long)(~0ULL >> 1) - 1);
printf("signed long long max:   %lld\n", (signed long long)(~0ULL >> 1));
printf("unsigned long long max: %llu\n", ~0ULL);

Demo

注意:char并不总是与signed char相同,所以我们需要使用signed char。但是,我们可以简单地使用 shortint 而不是 signed shortsigned int.


也就是说,正确且独立于平台的方法是使用编译器提供的定义。

#include <limits.h>

printf("signed char min:        %hhd\n", SCHAR_MIN);
printf("signed char max:        %hhd\n", SCHAR_MAX);
printf("unsigned char max:      %hhu\n", UCHAR_MAX);

printf("signed char min:        %hd\n", SHRT_MIN);
printf("signed char max:        %hd\n", SHRT_MAX);
printf("unsigned char max:      %hu\n", USHRT_MAX);

printf("signed int min:         %d\n", INT_MIN);
printf("signed int max:         %d\n", INT_MAX);
printf("unsigned int max:       %u\n", UINT_MAX);

printf("signed long min:        %ld\n", LONG_MIN);
printf("signed long max:        %ld\n", LONG_MAX);
printf("unsigned long max:      %lu\n", ULONG_MAX);

printf("signed long long min:   %lld\n", LLONG_MIN);
printf("signed long long max:   %lld\n", LLONG_MAX);
printf("unsigned long long max: %llu\n", ULLONG_MAX);

Demo