Какой самый портативный способ получить / установить старший бит целого числа в GNU C - PullRequest
8 голосов
/ 26 января 2011

Какой самый переносимый способ получить / установить старший бит целого числа в GNU C?

Это вопрос интервью Bloomberg. Я не дал лучший ответ в то время. Кто-нибудь может ответить на это?

Спасибо

Ответы [ 5 ]

5 голосов
/ 26 января 2011

Если тип без знака, это легко:

(type)-1-(type)-1/2

Для знаковых значений я не знаю способа.Если вы найдете способ, он ответит на несколько вопросов без ответа по SO:

C question: off_t (и другие целочисленные типы со знаком) минимальные и максимальные значения

Есть ли способ вычислить ширину целочисленного типа во время компиляции?

Может быть, другие.

5 голосов
/ 26 января 2011

Во-первых, обратите внимание, что нет переносимого способа доступа к старшему биту, если мы говорим о целых числах со знаком;в стандарте просто не определено ни одного переносимого представления, поэтому значение «старшего бита» может в принципе различаться.Кроме того, C не разрешает прямой доступ к побитовому представлению;вы можете обращаться к int как к буферу char, но вы не знаете, где находится «верхний бит».

Если нас интересует только неотрицательный диапазон целого числа со знаком, ипредполагая, что указанный диапазон имеет степень, равную степени двух (если нет, то нам нужно снова позаботиться о подписанном представлении):

#define INT_MAX_BIT (INT_MAX - (INT_MAX >> 1))
#define SET_MAX_BIT(x) (x | INT_MAX_BIT)
#define CLEAR_MAX_BIT(x) (x & ~INT_MAX_BIT)

Аналогичный подход может быть использован с неподписанными целочисленными значениями, где он можетиспользоваться для получения истинного старшего бита.

2 голосов
/ 26 января 2011

Вот глупый пример:

Built-in Function: int __builtin_clz (unsigned int x)

Returns the number of leading 0-bits in x, starting at the most
significant bit position. If x is 0, the result is undefined. 

Первая попытка:

int get_msb(int x) { return x ? __buildin_clz(x) == 0 : 0; }

Примечание: это особенность языка C, функции которого, задающие параметры int или unsigned int, могут вызываться с другим типом без предупреждения. Но это, вероятно, связано с преобразованием - стандарт C ++ 4.7.2 гласит:

Если тип назначения является беззнаковым, результирующее значение является целочисленным с наименьшим числом без знака, соответствующим исходному целому числу (по модулю 2n, где n - число битов, используемых для представления типа без знака). [Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). ]

Что означает, что битовая комбинация может быть изменена, если она не является представлением дополнения до двух, что также помешало бы надежной работе этого «решения». : - (

Комментарий Криса ниже предоставляет решение (включенное здесь как функция, а не макрос препроцессора):

int get_msb(int x) { return x ? __buildin_clz(*(unsigned*)&x) == 0 : 0; }
1 голос
/ 26 января 2011

Что не так с этим?

int get_msb(int n){
    return ((unsigned)n) >> (sizeof(unsigned) * CHAR_BIT - 1);
    // or, optionally
    return n < 0;
};

int set_msb(int n, int msb){
    if (msb)
         return ((unsigned)n) |  (1ULL << (sizeof(unsigned) * CHAR_BIT - 1));
    else return ((unsigned)n) & ~(1ULL << (sizeof(unsigned) * CHAR_BIT - 1));
};

Он заботится о порядке байтов, количестве битов в байте, а также работает с дополнением 1.

0 голосов
/ 17 июля 2015
#define HIGH_BIT(inttype) (((inttype)1) << (CHAR_BIT * sizeof(inttype) - 1))

пример использования:

ptrdiff_t i = 4711;
i |=  HIGH_BIT(ptrdiff_t);  /* set high bit */
i &= ~HIGH_BIT(ptrdiff_t);  /* clear high bit */
...