Почему в limits.h есть макросы _BIT для CHAR_BIT, LONG_BIT, WORD_BIT? Почему он не определяет INT_BIT?

Есть ли причина, по которой эти макросы определены для других типов, но не для int? Они устарели (не используются) с sizeof?

Я вижу, что они определены POSIX для limits.h

2
Evan Carroll 19 Сен 2018 в 01:18

2 ответа

Лучший ответ

Судя по документу, на который вы ссылаетесь, WORD_BIT - это то, кем вы хотите быть INT_BIT:

{WORD_BIT} Количество бит в объекте типа int.

Обратите внимание, что CX означает, что это расширение стандарта C.

В обосновании C99 говорится, что комитет не видел причин для чего-либо, кроме CHAR_BIT:

Макрос CHAR_BIT делает доступным количество бит в объекте типа char. Комитет C89 не видел особой пользы в добавлении таких макросов для других типов данных .

Скорее всего, потому что CHAR_BIT*sizeof(type) делает то, что вам нужно.

4
Shafik Yaghmour 18 Сен 2018 в 23:30

Вы можете сгенерировать их во время сборки, подсчитав биты в соответствующем беззнаковом максимуме.

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int popcnt(unsigned long long X) { int pc=0;for(;(X&1);pc++,X>>=1){;} return pc; }
int main()
{
    if(0>printf("#define CHAR_BIT %d\n", popcnt(UCHAR_MAX))) return EXIT_FAILURE;
    if(0>printf("#define UCHAR_BIT %d\n", popcnt(UCHAR_MAX))) return EXIT_FAILURE;
    if(0>printf("#define SCHAR_BIT %d\n", popcnt(UCHAR_MAX))) return EXIT_FAILURE;
    if(0>printf("#define SHRT_BIT %d\n", popcnt(USHRT_MAX))) return EXIT_FAILURE;
    if(0>printf("#define USHRT_BIT %d\n", popcnt(USHRT_MAX))) return EXIT_FAILURE;
    if(0>printf("#define INT_BIT %d\n", popcnt(UINT_MAX))) return EXIT_FAILURE;
    if(0>printf("#define UINT_BIT %d\n", popcnt(UINT_MAX))) return EXIT_FAILURE;
    if(0>printf("#define LONG_BIT %d\n", popcnt(ULONG_MAX))) return EXIT_FAILURE;
    if(0>printf("#define ULONG_BIT %d\n", popcnt(ULONG_MAX))) return EXIT_FAILURE;
    if(0>printf("#define LLONG_BIT %d\n", popcnt(ULLONG_MAX))) return EXIT_FAILURE;
    if(0>printf("#define ULLONG_BIT %d\n", popcnt(ULLONG_MAX))) return EXIT_FAILURE;
    if(0>fclose(stdout)) return EXIT_FAILURE;
    return EXIT_SUCCESS;
}

На моей платформе вышесказанное дает мне:

#define CHAR_BIT 8
#define UCHAR_BIT 8
#define SCHAR_BIT 8
#define SHRT_BIT 16
#define USHRT_BIT 16
#define INT_BIT 32
#define UINT_BIT 32
#define LONG_BIT 64
#define ULONG_BIT 64
#define LLONG_BIT 64
#define ULLONG_BIT 64

(Обратите внимание, что это технически не гарантируется, чтобы быть sizeof(the_type)*CHAR_BIT, поскольку стандарт C допускает биты заполнения в собственных типах.)

Если запуск этого фрагмента кода перед сборкой на какой-либо платформе, которую вы хотите поддерживать, вас раздражает, я вас понимаю.

Используя этот небольшой сценарий оболочки, вы можете сгенерировать (один раз для каждой платформы) идеально сохраняющий целочисленное-константное выражение без вызова UB-макроса (надеюсь) popcnt cpp-macro для целых чисел до N бит:

#!/bin/sh -eu
gen()
{
    Max=$1
    local i=0;
    prev='(X)'
    #continuous popcount at compile time
    printf '#define contpopcnt(X) %s\n' "(($prev&1)\\"
    i=1; while [ $i -le $Max ]; do
        #look 1 bit ahead the left shift never reaches or exceeds 
        #the width of whatever X's type might be (would be UB)
        prev="(($prev&2)?((X)>>$i):0)"
        printf '+(%s&1)\\\n' "$prev"
    i=$((i+1));done
    printf ')\n'
}

gen 256
cat<<EOF
//#define CHAR_BIT contpopcnt(UCHAR_MAX)
#define UCHAR_BIT contpopcnt(UCHAR_MAX)
#define SCHAR_BIT contpopcnt(UCHAR_MAX)
#define SHRT_BIT contpopcnt(USHRT_MAX)
#define USHRT_BIT contpopcnt(USHRT_MAX)
#define INT_BIT contpopcnt(UINT_MAX)
#define UINT_BIT contpopcnt(UINT_MAX)
#define LONG_BIT contpopcnt(ULONG_MAX)
#define ULONG_BIT contpopcnt(ULONG_MAX)
#define LLONG_BIT contpopcnt(ULLONG_MAX)
#define ULLONG_BIT contpopcnt(ULLONG_MAX)

//a little sanity check
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT!=contpopcnt(UCHAR_MAX)
    #error "oops"
#endif
EOF

А 256-битный вариант макроса составляет всего (!) 605 КБ. Так что вам действительно не нужны эти макросы *_BIT.

Редактировать:

Здесь гораздо более компактный способ: https://stackoverflow.com/a/4589384/1084774.

0
PSkocik 25 Ноя 2018 в 18:20