Имеет ли доступ к int с char * потенциально поведение undefined?

Ожидается, что код, приведенный ниже для проверки подлинности, будет иметь определенное поведение реализации:

int is_little_endian(void) {
    int x = 1;
    char *p = (char*)&x;
    return *p == 1;
}

Но возможно ли, что это может иметь поведение undefined на специально изобретенных архитектурах? Например, первый байт представления int со значением 1 (или другим хорошо выбранным значением) будет значением ловушки для типа char?

Как отмечено в комментариях, тип unsigned char не будет иметь этой проблемы, поскольку он не может иметь значения ловушки, но этот вопрос относится конкретно к типу char.

Ответ 1

Я не думаю, что Стандарт запретил бы реализацию, в которой signed char использовал формат знака-знака или один-дополнительный, и попал в ловушку при попытках загрузить бит-шаблон, который будет представлять "отрицательный ноль". Также не требует, чтобы такие реализации должны были сделать char без знака. Можно было бы изобрести архитектуру, в которой ваш код может иметь произвольное поведение. Еще несколько важных замечаний:

  • Нет никакой гарантии, что биты внутри char отображаются в той же последовательности, что и в int. Код не будет запускаться в UB-land, если биты не будут отображаться по порядку, но результат будет не очень значимым.

  • Насколько я могу судить, каждая неконкурентоспособная соответствующая реализация C99 использовала формат "два дополнения"; Я считаю сомнительным, что любой когда-либо будет делать иначе.

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

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

Можно было бы создать подходящую реализацию знаковой величины, в которой целочисленное значение 1 будет иметь битовый шаблон, который будет кодировать подписанное значение char "отрицательный ноль" и которое будет ловушке при попытке загрузить его. Можно было бы даже придумать реализацию соответствующих дополнений, которые сделали это (у них есть много бит заполнения в типе "int", все из которых устанавливаются при сохранении значения "1" ). Учитывая, что можно было бы разработать соответствующую реализацию, которая использует правило единой программы, чтобы оправдывать выполнение чего-либо, что ему понравилось, с помощью вышеупомянутого исходного текста, независимо от того, какой целочисленный формат он использует, однако я не думаю, что вероятность странного типа char должна действительно быть беспокойством.

Заметьте, кстати, что Стандарт не прилагает никаких усилий, чтобы запретить глупые реализации; он может быть улучшен путем добавления языка, в соответствии с которым char должен быть либо двухкомпонентным, либо без символьных представлений, либо неподписанным типом, либо обязательным для него значением signed char, либо явно указывая, что это не требуется. Он также может быть улучшен, если он распознает категорию реализаций, которые не могут поддерживать такие типы, как unsigned long long [который был бы основным камнем преткновения для 36-битных систем дополнения и может быть причиной того, что не соответствует C99 для таких платформ существуют реализации].

Ответ 2

Per C 2011 [N1570] 6.2.5 15, char ведет себя как signed char или unsigned char. Предположим, что оно signed char. 6.2.6.2 2 обсуждать знаковые целочисленные типы, включая signed char. В конце этого параграфа говорится:

Какое из этих [знака, величины, двойного дополнения или одного дополнения] применяется, определяется реализацией, равно как и значение со знаковым битом 1 и всеми битами значения 0 (для первых двух) или со знакомным битом и все биты значений 1 (для одного дополнения) представляют собой ловушечное представление или нормальное значение.

Таким образом, этот абзац позволяет signed char иметь ловушку. Я не знаю ни одной части стандарта C, которая противоречит этому. Таким образом, доступ к байтам int через a char * может считывать представление ловушки и, следовательно, может иметь поведение undefined.

Конкретное значение 1 в int не приведет к представлению ловушки в char для любой нормальной реализации C, поскольку 1 будет находиться в самом "правом" (младшем значении) бите некоторого байта int, и никакая нормальная реализация C не помещает бит знака char в бит в этой позиции. Однако стандарт C, по-видимому, не запрещает такую ​​компоновку, поэтому теоретически значение int со значением 1 может быть закодировано битами 00000001 в одном из его байтов, и эти биты могут быть ловушечным представлением для char.

Ответ 3

Я нашел цитату из Стандарта, которая доказывает, что никакое представление объекта не является значением ловушки для unsigned char:

6.2.6.2 Целочисленные типы

1 Для целых чисел без знака, отличных от без знака char,, бит объекта представление делится на две группы: биты значений и биты заполнения (необходимо не быть последним). Если бит N значений бит, каждый бит должен представлять собой мощность 2 между 1 и 2N-1, чтобы объекты такого типа были способны представляющие значения от 0 до 2N - 1 с использованием чистого двоичного представления; это должно быть известный как представление значения. Значения любых битов дополнений не определены .53)

Предыдущее говорит, что unsigned char не может иметь никаких добавочных битов.

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

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

Итак, я думаю, что ответ заключается в том, что char не гарантированно не имеет значений ловушек, но unsigned char есть.