Нет, это не так, но это только потому, что память была выделена и записана с использованием символьного типа.
Память выделяется с помощью malloc. Этот объект не имеет объявленного типа1, потому что он был выделен с помощью malloc. Таким образом, объект не имеет эффективного типа.
Затем код обращается к объекту и изменяет его, используя тип char
. Поскольку тип 2 char
и ни один объект, имеющий эффективный тип, не копируется5, при копировании эффективный тип не устанавливается равным char
для этого и последующих обращений, а задается эффективный тип на char
, только на время доступа3. После доступа объект больше не имеет эффективного типа.
Затем тип int
используется для доступа и только для чтения этого объекта. Поскольку у объекта нет эффективного типа, он становится 3 int
на время чтения. После доступа объект больше не имеет эффективного типа. Поскольку int
был явно совместим с эффективным типом int
, поведение определено.
(Предполагая, что считанные значения не являются представлением ловушки для int
.)
Если бы вы получили доступ к объекту и изменили его, используя несимвольный тип, который также несовместим с int
, поведение было бы неопределенным.
Допустим, ваш пример был (при условии sizeof(float)==sizeof(int)
):
int i;
void *buf = calloc(5, sizeof(float)); // buf initialized to 0
{
float *ptr1 = buf;
for(i = 0; i < 5*sizeof(float); ++i)
ptr1[i] = (float)i;
}
int *ptr2 = buf;
for(i = 0; i < 5; ++i)
printf("%d", ptr2[i]);
Эффективный тип объекта, когда записываются float
, становится типом float
на время записи и всех последующих обращений к объекту, которые не изменяют его2. Когда к этим объектам затем обращается int
, эффективный тип остается float
, так как значения только считываются, а не изменяются. Предыдущая запись с использованием float
навсегда установила эффективный тип float
до следующей записи в этот объект (чего в данном случае не произошло). Типы int
и float
несовместимы4, поэтому поведение не определено.
(Весь приведенный ниже текст взят из: ISO:IEC 9899:201x)
1 (6.5 Выражения 6)
Эффективным типом объекта для доступа к его хранимому значению является объявленный тип объекта, если он есть. 87) Размещенные объекты не имеют объявленного типа.
2 (6.5 Выражения 6)
Если значение хранится в объекте, не имеющем объявленного типа, через lvalue, имеющее тип, не являющийся символьным типом, то тип lvalue становится эффективным типом объекта для этого доступа и для последующих доступов, которые не изменяют сохраненное значение.
3 (6.5 Выражения 6)
Для всех других обращений к объекту, не имеющему объявленного типа, эффективным типом объекта является просто тип lvalue, используемый для доступа.
4 (6.5 Выражения 8)
Доступ к хранимому значению объекта должен осуществляться только выражением lvalue, имеющим один из следующих типов: 88) — тип, совместимый с действующим типом объекта , — уточненная версия типа, совместимая с действующим типом объекта, — тип, который является подписанным или беззнаковым типом, соответствующим эффективному типу объекта, — тип, который является подписанным или беззнаковым типом, соответствующим уточненному типу версия эффективного типа объекта, - агрегатный тип или тип объединения, который включает один из вышеупомянутых типов среди своих членов (включая, рекурсивно, член подагрегата или содержащегося объединения), или - символьный тип.
5 (6.5 Выражения 6)
Если значение копируется в объект, не имеющий объявленного типа, с помощью memcpy или memmove, или копируется как массив символьного типа, то эффективный тип измененного объект для этого доступа и для последующих доступов, которые не изменяют значение, является эффективным типом объекта, из которого копируется значение, если он есть.
person
2501
schedule
13.07.2016