Подтвердить что ты не робот

Что говорят стандарты C и С++ о представлении и манипуляции на уровне битов?

Я знаю, что стандарты C и С++ не определяют конкретное представление чисел (могут быть два дополнения, знак и величина и т.д.). Но я не знаю стандартов достаточно хорошо (и не мог найти, если он заявил), чтобы знать, есть ли какие-либо конкретные ограничения/гарантии/зарезервированные представления, сделанные при работе с битами. В частности:

  • Если все биты целочисленного типа равны нулю, целое число целых равно нулю?
  • Если какой-либо бит целочисленного типа равен единице, то целое число в целом представляет ненулевое значение? (если это "да", тогда некоторые представления, такие как знак и величина, будут дополнительно ограничены)
  • Есть ли гарантированный способ проверить, не установлен ли какой-либо бит?
  • Есть ли гарантированный способ проверить, установлен ли какой-либо бит? (# 3 и # 4 зависят от # 1 и # 2, потому что я знаю, как установить, например, 5-й бит (см. # 5) в некоторой переменной x, и я бы хотел проверить переменную y, чтобы узнать, будет ли это 5-й бит 1, я хотел бы знать, будет ли работать if (x & y) (потому что, как я понимаю, это зависит от значения представления, а не от того, действительно ли этот бит равен 1 или 0))
  • Есть ли гарантированный способ установить самые левые и/или самые правые биты? (По крайней мере, проще, чем принимать char c со всеми битами true (устанавливается c = c | ~c) и делать c = c << (CHAR_BIT - 1) для установки высоких бит и c = c ^ (c << 1) для младших бит, предполагая, что я не делаю любые предположения, которые я должен был бы, учитывая эти вопросы)
  • Если ответ на # 1 "нет", как можно перебрать биты в целочисленном типе и проверить, был ли каждый из них 1 или 0?

Я предполагаю, что мой общий вопрос: существуют ли какие-либо ограничения/гарантии/зарезервированные представления, сделанные стандартами C и С++ относительно битов и целых чисел, несмотря на то, что целочисленное представление не является обязательным (и если стандарты C и С++ отличаются в этом отношении, какова их разница)?

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

Изменить: Что касается того, что я называю "битами", я имею в виду "биты формирования значения", и я не включаю "биты заполнения".

4b9b3361

Ответ 1

(1) Если все биты целочисленного типа равны нулю, целое число целых чисел равно нулю?

Да, битовая диаграмма, состоящая из всех нулей, всегда представляет 0:

Представления интегральных типов должны определять значения с использованием чистой двоичной системы нумерации. 49 [§3.9.1/7]

49 Позиционное представление для целых чисел, которое использует двоичные цифры 0 и 1, в которых значения, представленные последовательными битами, являются аддитивными, начинаются с 1 и умножаются на последовательную интегральную мощность 2, кроме, возможно, для бит с наивысшим положением.


(2) Если какой-либо бит в целочисленном типе равен единице, то целое число в целом представляет ненулевое значение? (если это "да", тогда некоторые представления, такие как знак и величина, будут дополнительно ограничены)

Нет. Фактически, допустимая величина знака определенно разрешена:

[Пример: этот международный стандарт разрешает комплексирование 2s, 1s дополнение и подписанные представления величины для интегральных типов. -конец пример] [§3.9.1/7]


(3) Есть ли гарантированный способ проверить, не установлен ли какой-либо бит?

Я считаю, что ответ на этот вопрос "нет", если вы считаете подписанные типы. Это эквивалентно тестированию равенства с битовой схемой всех, что возможно только в том случае, если у вас есть способ создать подписанное число с битовой схемой всех. Для беззнакового числа это представление гарантировано, но приведение из без знака в подпись undefined, если число недопредставлено:

Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение определяется реализацией. [§4.7/3]


(4) Есть ли гарантированный способ проверить, установлен ли какой-либо бит?

Я так не думаю, потому что допустимая величина знака равна -0 будет сравниваться с -0. Но это должно быть возможно с неподписанными числами.


(5) Есть ли гарантированный способ установить самые левые и/или самые правые биты?

Опять же, я считаю, что ответ "да" для неподписанных номеров, но "нет" для подписанных номеров. Сдвиги undefined для отрицательных номеров:

В противном случае, если E1 имеет подписанный тип и неотрицательное значение, а E1 × 2 E2 представляется в типе результата, то это результирующее значение; в противном случае поведение undefined. [пункте 5.8/2]

Ответ 2

Вы используете термин "все биты" несколько раз, но вы не уточняете, какие "все биты" вы имеете в виду. Представление объектов целочисленных типов в C/С++ может включать в себя биты формирования значений и биты заполнения. Единственный целочисленный тип, который, как гарантируется, не имеет битов заполнения, равен [signed/unsigned] char.

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

Что касается битов дополнения, вещи/были немного сложнее. Исходная спецификация языка C (C89/90, а также оригинальная C99) не гарантировала, что установка всех битов объекта на нуль привела к действительному целочисленному представлению. Это могло вызвать недопустимое представление ловушки. То есть в исходном C (и даже в C99) с использованием memset(..., 0, ...) для целочисленных типов не гарантирует, что объекты получат действительные нулевые значения (за исключением [signed/unsigned] char). Это было изменено в более поздних спецификациях, а именно в одном из технических исправлений для C99. Теперь требуется, чтобы шаблон с нулевым битом в целочисленном объекте (который включает в себя все биты, включая прописные), представляет действительное нулевое значение.

т.е. в современном C законно использовать memset(..., 0, ...) для установки любых целых объектов в ноль, но это стало законным только после C99.

Ответ 3

У вас уже есть некоторые ответы о представлении целочисленных значений. Существует точно один способ, который гарантированно даст вам все отдельные биты любого объекта, который представлен в памяти: просмотрите его как массив unsigned char. Это единственный интегральный тип, который не имеет битов дополнений и, как гарантируется, не имеет представления о ловушке. Поэтому приведение указателя типа T* к вашему объекту в unsigned char* всегда будет работать, если вы только получаете доступ к первым байтам sizeof(T). Благодаря этому вы можете проверить и установить все байты (и, следовательно, биты) по своему вкусу.

Если вас интересует более подробная информация, здесь я написал что-то о анатомии целых типов в C. С++ может немного отличаться от этого, в частности, тип puning через union, как описано, в С++ явно не определен.

Ответ 4

Q: Если какой-либо бит в целочисленном типе равен единице, то целое в целом представляет ненулевое значение? (если это "да", тогда некоторые представления, такие как знак и величина, будут дополнительно ограничены)

Нет. Стандарты для C и С++ не исключают подписанную величину или одно дополнение, оба из которых имеют +0 и -0. В то время как +0 и -0 должны сравнивать равные, но они не должны иметь одинаковое представление.

Удачи найти машину в настоящее время, которая использует подписанную величину или одно дополнение.

Ответ 5

Если все биты целочисленного типа равны нулю, целое число целых равно нулю?

Изменить: поскольку теперь вы выяснили, что вас не интересуют биты заполнения, ответ на это на самом деле "да". Но я оставляю оригинал:

Не обязательно, это может быть ловушка. См. C99 6.2.6.1:

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

Наличие битов заполнения допускает возможность того, что все 0 являются ловушками. (Как отметил Кит Томпсон в приведенном ниже комментарии, в более позднем C11 четко указано, что такое представление не является ловушкой).

и

Значения любых битов дополнений не определены

и

44). Некоторые комбинации битов дополнений могут генерировать ловушки представления

Если вы ограничиваете вопрос значением и подписываете биты, ответ да, из-за 6.2.6.2:

Если бит N значений бит, каждый бит должен представлять собой мощность 2 от 1 до 2 N -1, так что объекты этого типа должны быть способны отображать значения от 0 до 2 N - 1 с использованием чистого двоичного представления; это должно быть известно как представление значения.

и

Если знаковый бит равен нулю, он не должен влиять на результирующее значение.

Если какой-либо бит целочисленного типа равен единице, то целое число в целом представляет ненулевое значение? (если это "да", тогда некоторые представления, такие как знак и величина, будут дополнительно ограничены)

Не обязательно, и на самом деле знак и величина явно поддерживаются в 6.2.6.2.

Есть ли гарантированный способ проверить, не установлен ли какой-либо бит?

Если вам не нужны прописные и знаковые биты, вы можете просто сравнить с 0, но это не сработало бы с 1 дополнением (которое разрешено), поскольку все биты 0 и все биты 1 оба представляют значение 0.

В противном случае: вы можете прочитать значение каждого байта с помощью unsigned char * и сравнить результат с 0:

Значения, хранящиеся в неподписанных битовых полях и объектах типа unsigned char должны быть представлены с использованием чистой двоичной нотации

Если вы хотите проверить бит определенного значения, вы можете построить подходящую битовую маску, используя (1u < n), но это не обязательно позволит вам проверить бит знака.

Есть ли гарантированный способ проверить, установлен ли какой-либо бит?

Ответ по существу тот же, что и в предыдущем вопросе.

Есть ли гарантированный способ установить самые левые и/или самые правые биты?

Вы имеете в виду бит слева? Вы можете считать биты в INT_MAX или UINT_MAX или эквивалент в зависимости от типа и использовать это для построения значения (через 1 << n), с которым OR или исходное значение.

Если ответ на # 1 "нет", как можно перебрать биты в целочисленном типе и проверить, был ли каждый из них 1 или 0?

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

Ответ 6

Если вы хотите, чтобы ваш мозг взорвался, подумайте об этом: если вы интерпретируете int или long or long long как массив unsigned char (что наиболее разумно, если вы хотите увидеть все биты), вы знаете, что порядок байтов не определен, например, "bigendian" и "littleendian". Мы все (надеюсь) знаем об этом.

Но это хуже: каждый бит int может храниться в любом из битов массива char. Так что есть 32! как биты 32-битного целого могут быть сопоставлены с массивом из четырех 8-разрядных символов без знака по-настоящему странной реализации. К счастью, я не встречал больше двух способов (и я знаю еще одного порядка на реальном компьютере).

Ответ 7

Для битманипуляций вы можете создать структуру с 8-мя неподписанными битовыми полями и указать указатель этой структуры на ваш char. Таким образом, вы можете легко получить доступ к каждому биту. Но компилятор, вероятно, сделает маскировку под капотом, поэтому я считаю это более чистым способом. Вы должны проверить, что ваш компилятор не изменит порядок полей при этом.

yourstruct* pChar=(yourstruct*)(&c)
pChar.Bit7=1;

Ответ 8

Позвольте мне предостеречь это, сказав, что я обращаюсь к C и С++ вообще (например, C90 и ниже, MS Visual С++ и т.д.): "самый общий общий знаменатель" (по сравнению с последним/самым лучшим стандартом cx11).

Q: Если все биты целочисленного типа равны нулю, целое число целых чисел равно нулю?

A: Да

Q: Если какой-либо бит в целочисленном типе равен единице, то целое в целом представляет ненулевое значение? (если это "да", тогда некоторые представления, такие как знак и величина, будут дополнительно ограничены)

A: Да. Это включает в себя знаковый бит для подписанного int. Я откровенно не знаком с "величиной"

Q: Есть ли гарантированный способ проверить, не установлен ли какой-либо бит?

A: "And'ing" битмаска всегда гарантируется.

Q: Есть ли гарантированный способ проверить, установлен ли какой-либо бит?

A: Опять же, "and'ing" битмаска всегда гарантируется.

Q: Есть ли гарантированный способ установить самые левые и/или самые правые биты?

A: Я считаю, что у вас всегда должен быть "MAX_INT", доступный для всех реализаций/всех архитектур, чтобы определить самый левый бит.

Я готов загореться... но я верю, что это верно. И я надеюсь, что это поможет.

ИМХО...