Строгое сглаживание не позволяет нам получить доступ к одному и тому же месту памяти с помощью несовместимого типа.
int* i = malloc( sizeof( int ) ) ; //assuming sizeof( int ) >= sizeof( float )
*i = 123 ;
float* f = ( float* )i ;
*f = 3.14f ;
это было бы незаконным в соответствии со стандартом C, потому что компилятор "знает", что int
не может получить доступ к float
lvalue.
Что делать, если я использую этот указатель для указания правильности памяти, например:
int* i = malloc( sizeof( int ) + sizeof( float ) + MAX_PAD ) ;
*i = 456 ;
Сначала я выделяю память для int
, float
, а последняя часть - это память, которая позволит сохранять float
на выровненном адресе. float
требует выравнивания по кратным 4. MAX_PAD
обычно составляет 8 из 16 байтов в зависимости от системы. В любом случае MAX_PAD
достаточно велик, поэтому float
можно правильно выровнять.
Затем я пишу a int
в i
, насколько это хорошо.
float* f = ( float* )( ( char* )i + sizeof( int ) + PaddingBytesFloat( (char*)i ) ) ;
*f= 2.71f ;
Я использую указатель i
, увеличиваю его с размером int
и правильно выравниваю его с помощью функции PaddingBytesFloat()
, которая возвращает количество байтов, необходимых для выравнивания float
, заданного адреса. Затем я пишу в него поплавок.
В этом случае f
указывает на другую ячейку памяти, которая не перекрывается; он имеет другой тип.
Вот некоторые части из стандарта (ISO/IEC 9899: 201x) 6.5, на которые я ссылался при написании этого примера.
Алиасинг - это когда более одного значения lLame указывает на то же место памяти. Стандарт требует, чтобы эти lvalues имели совместимый тип с эффективным типом объекта.
Что такое эффективный тип, цитата из стандарта:
Эффективным типом объекта для доступа к его сохраненному значению является объявленный тип объект, если таковой имеется .87) Если значение хранится в объекте, не имеющем объявленного типа, через lvalue, имеющий тип, который не является типом символа, тогда тип lvalue становится эффективный тип объекта для этого доступа и для последующих доступов, которые не изменяются сохраненное значение. Если значение копируется в объект, не имеющий объявленного типа, используя memcpy или memmove, или копируется как массив типа символа, тогда эффективный тип измененного объекта для этого доступа и для последующих доступов, которые не изменяют value - это эффективный тип объекта, из которого копируется значение, если оно есть. Для всех других доступов к объекту, не имеющему объявленного типа, эффективный тип объекта просто тип lvalue, используемый для доступа.
87) Выделенные объекты не имеют объявленного типа.
Я пытаюсь соединить куски и выяснить, разрешено ли это. В моей интерпретации эффективный тип выделенного объекта может быть изменен в зависимости от типа lvalue, используемого в этой памяти, из-за этой части: For все другие обращения к объекту, не имеющему объявленного типа, эффективный тип объекта - это просто тип lvalue, используемый для доступа.
Является ли это законным? Если нет, что, если я использовал указатель void как lvalue вместо int pointer i
в моем втором примере? Если даже это не сработает, что делать, если я получил адрес, который присваивается указателю float во втором примере, как memcopied значение, и этот адрес никогда не использовался как lvalue раньше.