C вопрос: добавление битов в целые числа без знака и побитовые операции (C89)

У меня есть много кода, который выполняет побитовые операции с целыми целыми знаками. Я написал свой код с предположением, что эти операции были на целых числах с фиксированной шириной без каких-либо битов заполнения. Например, массив из 32-битных беззнаковых целых чисел, из которых все 32 бита доступны для каждого целого.

Я хочу сделать мой код более портативным, и я сосредоточен на том, чтобы убедиться, что я совместим с C89 (в данном случае). Одна из проблем, с которыми я столкнулась, - это возможные пронумерованные целые числа. Возьмите этот крайний пример, взятый из руководства GMP:

Однако на векторных системах Cray можно отметить, что short и int всегда хранятся в 8 байтах (и с указанием sizeof, указывающим это), но используют только 32 или 46 бит. Функция ногтей может учитывать это, передавая, например, 8 * sizeof (int) -INT_BIT.

Я также читал об этом типе дополнений в других местах. Я на самом деле прочитал сообщение о SO прошлой ночью (простите меня, у меня нет ссылки, и я собираюсь привести что-то похожее из памяти), где, если у вас есть, скажем, двойник с 60 полезными битами, остальные 4 могут можно использовать для заполнения, и эти биты дополнений могут служить некоторым внутренним целям, поэтому они не могут быть изменены.


Итак, скажем, например, мой код компилируется на платформе, где тип unsigned int имеет размер 4 байта, каждый байт составляет 8 бит, однако наиболее значимые 2 бита являются битами заполнения. Будет ли UINT_MAX в этом случае 0x3FFFFFFF (1073741823)?

#include <stdio.h>
#include <stdlib.h>

/* padding bits represented by underscores */
int main( int argc, char **argv )
{
    unsigned int a = 0x2AAAAAAA; /* __101010101010101010101010101010 */
    unsigned int b = 0x15555555; /* __010101010101010101010101010101 */
    unsigned int c = a ^ b; /* ?? __111111111111111111111111111111 */
    unsigned int d = c << 5; /* ??  __111111111111111111111111100000 */
    unsigned int e = d >> 5; /* ?? __000001111111111111111111111111 */

    printf( "a: %X\nb: %X\nc: %X\nd: %X\ne: %X\n", a, b, c, d, e );
    return 0;
}

безопасно ли XOR два целых числа с битами заполнения?
не будет ли я XOR любыми битами заполнения?
Я не могу найти это поведение, описанное в C89.
кроме того, c var гарантированно будет 0x3FFFFFFF, или если, например, два бита дополнений были включены в или b, то c будет 0xFFFFFFFF?
тот же вопрос с d и e. Могу ли я манипулировать битами заполнения путем смещения? Я ожидал бы увидеть это ниже, предполагая 32 бита с двумя наиболее значимыми битами, используемыми для заполнения, но я хочу знать, гарантировано ли что-то вроде этого:

a: 2AAAAAAA
b: 15555555
c: 3FFFFFFF
d: 3FFFFFE0
e: 01FFFFFF

Также биты заполнения всегда являются самыми значимыми битами или могут быть наименее значимыми битами?

Спасибо, ребята,


EDIT 12/19/2010 5 вечера EST: Кристоф ответил на мой вопрос. Спасибо!
Я также спросил (выше), являются ли биты заполнения самыми важными битами. Это цитируется в обосновании стандарта C99, а ответ - нет. Я играю в это безопасно и предполагаю то же самое для C89. Вот конкретно то, что объясняет C99 для §6.2.6.2 (представление целых типов):

Биты заполнения являются доступными для пользователя в неподписанном целочисленном типе. Например, предположим, что машина использует пару 16-разрядных шорт (каждая со своим собственным битом знака) для создания 32-битного int, а бит знака младшего короткого замыкания игнорируется при использовании в этом 32-битном int. Затем, как 32-битный подписанный int, есть бит заполнения (в середине 32 бит), который игнорируется при определении значения 32-разрядного подписанного int. Но если этот 32-битный элемент рассматривается как 32-разрядный беззнаковый int, то этот бит заполнения отображается для программы пользователя. Комитету С было сказано, что есть машина, которая работает таким образом, и это одна из причин того, что биты дополнений были добавлены в C99.

В сносках 44 и 45 упоминаются, что биты четности могут быть битами заполнения. Комитет не знает о каких-либо машинах с доступными пользователем битами четности в пределах целого числа. Поэтому комитет не знает о каких-либо машинах, которые обрабатывают биты четности как биты заполнения.


EDIT 12/28/2010 3PM EST. Я нашел интересную дискуссию о comp.lang.c несколько месяцев назад.
Побитовые эффекты оператора на битах заполнения (читатель VelocityReviews)
Побитовые эффекты оператора на битах заполнения (альтернативная ссылка Google Groups)
Один момент, сделанный Dietmar, который я нашел интересным:

Отметим, что биты заполнения не нужны для существования ловушных представлений; также будут выполняться комбинации битов значений, которые не представляют собой значение типа объекта.

Ответы

Ответ 1

Побитовые операции (например, арифметические операции) работают с значениями и игнорируют заполнение. Реализация может или не может изменять биты заполнения (или использовать их внутренне, например, как биты четности), но портативный код C никогда не сможет обнаружить это. Любое значение (включая UINT_MAX) не будет включать дополнение.

Если целочисленное дополнение может привести к проблемам, это если вы используете такие вещи, как sizeof (int) * CHAR_BIT, а затем попробуйте использовать сдвиги для доступа ко всем этим битам. Если вы хотите быть переносимым, используйте только (unsigned) char, целые числа фиксированного размера (дополнение C99) или программно определить количество битов значений. Это можно сделать во время компиляции с препроцессором, сравнив UINT_MAX с полномочиями 2 или во время выполнения с помощью бит-операций.

изменить

В C90 не упоминается целочисленное дополнение, но, насколько я могу судить, "невидимые" предшествующие или завершающие биты целочисленного бита не должны нарушать стандарт (я не прошел через все соответствующие разделы, чтобы убедиться, что это действительно, случай); там probaby - проблемы со смешанными дополнениями и битами значения, упомянутые в обосновании C99, поскольку в противном случае стандарт не нужно было бы изменять.

Что касается значения доступного для пользователя: биты заполнения доступны, поскольку вы можете в любом случае получить бит foo (включая дополнение) с помощью бит-операций на ((unsigned char *)&foo)[…]. Однако будьте осторожны при изменении битов дополнений: результат не изменит значение целого числа, но, тем не менее, может создать ловушку-представление. В случае C90 это неявно неопределено (как и вообще не упоминается), в случае C99, оно определяется реализацией.

Это не то, о чем говорилось в цитате с обоснованием: цитированная архитектура представляет 32-битные целые числа через два 16-битных целых числа. В случае неподписанных типов результирующее целое число имеет 32 бита значений и точность 32; в случае знаковых целых чисел он имеет только 31 бита значений и точность 30: один из знаковых битов 16-разрядных целых чисел используется в качестве знакового бита 32-разрядного целого числа, другой игнорируется, тем самым создавая бит заполнения, окруженный битами значения. Теперь, если вы получаете доступ к 32-разрядному значению целого числа как целое без знака (которое явно разрешено и не нарушает правила псевдонимов C99), бит дополнений становится битом значения, доступным для пользователя.