Итак, я бился головой о Строгом Правиле Псевдонима и действующих правилах типа за последние пару дней. Хотя дух этого достаточно ясен, я бы хотел получить хорошее техническое понимание правил. Пожалуйста, обратите внимание, что я рассмотрел много связанных вопросов по SO, но я не чувствую, что на вопросы, которые будут представлены здесь, были даны ответы таким образом, который действительно находится со мной в любом другом месте.
Этот вопрос разделен на две части.
В первой части я делю правила эффективного типа на предложения и объясняю свое понимание каждой из них. Для каждого из них, пожалуйста, подтвердите мое понимание, если оно правильное, или исправьте меня, если оно ошибочно, и объясните, почему это так. В последнем «предложении» я также представляю два вопроса, на которые я был бы признателен за ответы.
Вторая часть вопроса касается моего понимания SAR.
Часть 1: Правила действующего типа
Предложение 1
Действительным типом объекта для доступа к его сохраненному значению является объявленный тип объекта, если есть.
Это довольно ясно - объявленный объект, такой как int x
, имеет постоянный эффективный тип, то есть тот тип, с которым он объявлен (в данном случае int
).
Предложение 2
Если значение сохраняется в объекте без объявленного типа через lvalue, имеющий тип, который не является символьным типом, тогда тип lvalue становится эффективным типом объекта для этого доступа и для последующих доступов, которые не изменяют сохраненное значение.
«Объект, не имеющий объявленного типа», как правило, является динамически размещаемым объектом.
Когда мы храним данные внутри выделенного объекта (, независимо от того, имеет ли он уже эффективный тип ), эффективным типом объекта становится тип lvalue, используемый для доступа к данным для хранения (если только lvalue не имеет символа тип). Например:
int* x = malloc(sizeof(int)); // *x has no effective type yet
*x = 10; // *x has effective type int, because the type of lvalue *x is int
Также можно изменить эффективный тип объекта, который уже имеет эффективный тип. Например:
float* f = (float*) x;
*f = 20.5; // *x now has effective type float, because the type of lvalue *f is float.
Предложение 3
Если значение копируется в объект, не имеющий объявленного типа, используя memcpy или memmove, или копируется как массив символьного типа, тогда действующий тип измененного объекта для этого доступа и для последующих обращений, которые не изменяют значение, является эффективным типом объекта, из которого копируется значение, если оно имеет его.
Это означает, что когда мы устанавливаем значение в выделенный объект, если значение устанавливается через lvalue типа, совместимого с char*
(или через memcpy
и memmove
), эффективный тип Объект становится эффективным типом данных, которые копируются в него. Например:
int* int_array = malloc(sizeof(int) * 5); // *int_array has no effective type yet
int other_int_array[] = {10, 20, 30, 40, 50};
char* other_as_char_array = (char*) other_int_array;
for (int i = 0; i < sizeof(int) * 5; i++) {
*((char*) int_array + i) = other_as_char_array[i];
}
// *int_array now has effective type int
Предложение 4
Для всех других обращений к объекту, не имеющему объявленного типа, эффективным типом объекта является просто тип lvalue, используемого для доступа.
У меня есть два вопроса относительно этой части:
A. Под " для всех других доступов " означает ли текст просто "для всех чтение доступов"?
Мне кажется, что все предыдущие правила, которые относятся к объекты необъявленных типов, имеют дело только с и хранят значение. Так является ли это простым правилом для любой операции read против объекта необъявленного типа (который может иметь или не иметь эффективный тип)?
B. Определенный объект в памяти имеет только один эффективный тип. Итак, что означает текст «Для всех других доступов » ... Это не вопрос доступа, это вопрос объективного эффективного типа объекта. Не так ли? Пожалуйста, уточните язык текста.
Часть 2: Вопрос о строгом алиасинге
Описание правила строгого алиасинга начинается примерно так (выделено мной):
Объект должен иметь свое хранимое значение, доступ к которому возможен только через выражение lvalue, которое имеет один из следующих типов [...]
Когда текст говорит «сохраненное значение» доступ "- означает ли это доступ как для чтения, так и для записи, или только для чтения?
В качестве другого способа задать этот вопрос: представляет ли следующий код нарушение строгого псевдонима или это законно?
int* x = malloc(sizeof(int)); // *x - no effective type yet
*x = 8; // *x - effective type int
printf("%d \n", *x); // access the int object through lvalue *x
float* f = (float*) x; // casting itself is legal
*f = 12.5; // effective type of *x changes to float - *** is this a SAR violation? ***
printf("%g \n", *f); // access the float object through lvalue *f