Является ли тип наказания через указатель объединения допустимым в C? - PullRequest
1 голос
/ 06 октября 2019

Этот вопрос основан на коде этого вопроса , скопированном ниже, который делает неправильное наложение типов с помощью указателя:

# include <stdio.h>
int main()
{
    char p[]={0x01,0x02,0x03,0x04};
    int *q = p;
    printf("%x",*q);
    return 0;
}

Мой вопрос заключается в следующемверсия приведенного выше кода законна? Я больше всего не уверен насчет приведения указателя на char к указателю на объединение, содержащее массив char. Здесь, в SO, много вопросов о штамповке типов, но я не нашел дубликат, который охватывает использование указателя таким образом.

#include <stdio.h>
#include <stdint.h>

union char_int {
    char p[4];
    int32_t q;
};

int main()
{
    char p[]={0x01,0x02,0x03,0x04};
    int *q = &(((union char_int *)p)->q);
    printf("%x",*q);
    return 0;
}

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

1 Ответ

0 голосов
/ 10 октября 2019

Значение «объект должен иметь свое сохраненное значение, доступное только через выражение lvalue, имеющее один из следующих типов ...», зависит от того, как определяются слова «объект» и «по», используемые в этом правиле. ,Насколько я могу судить, никогда не было ничего похожего на консенсус в отношении того, что означают эти слова, за исключением того факта, что авторы Стандарта предположительно ожидали, что реализации попытаются толковать правило разумно. Обратите внимание, что при буквальной интерпретации правила что-то вроде:

short volatile x;
int test(void)
{
  int y = x+1;
  return y;
}

будет вызывать UB, потому что время жизни y начинается, когда код вводит test, что, в свою очередь, происходит до того, как x будет прочитано, ноон не может получить значение, пока не будет прочитано x. Следовательно, значение y должно измениться в течение его времени жизни, но такое действие не включает ни lvalue-выражения типа int, ни какого-либо другого допустимого типа.

Ясно, что такая интерпретация была бы абсурдной, ноПравило, которое исключает прямые случаи на предположении, что реализации будут знать, что делать, нельзя полагаться на рассмотрение более сложных. Что касается рассматриваемой конструкции, некоторые компиляторы сказали бы, что в выражении lvalue, таком как someUnion.member = 23;, объект объединения изменяется «посредством» выражения lvalue someUnion, но не обязательно допускает возможность того, что такой объект можетбыть доступным в другом месте ни lvalue типа члена, ни lvalue других типов объединения, содержащих тот же член. Однако без какой-либо ясности относительно того, что подразумевается под словом «мимо», невозможно реально охарактеризовать какую-либо конкретную интерпретацию как правильную или неправильную.

...