2016-01-19 3 views
6

Рассмотрим следующий фрагмент кода:указатель арифметика на неконтактного типа массива

struct Blob { 
    double x, y, z; 
} blob; 

char* s = reinterpret_cast<char*>(&blob); 
s[2] = 'A'; 

Если предположить, что SizeOf (двойных) 8, делает этот код триггера неопределенное поведение?

+4

Это было бы даже не скомпилировано без броска. – dgross

+0

Это C? В C++ это не будет компилироваться. – Bathsheba

+1

Это не законный C или C++, вам нужен актерский состав. Когда у вас есть актерский состав, это законно и четко определено. Конечно, все может случиться, если вы попытаетесь получить доступ к blob.x впоследствии. –

ответ

5

Цитируя N4140 (примерно 14 C++):

3.9 Типы [basic.types]

2 Для любого объекта (кроме базового класса подобъекта) из тривиальных копируемых тип T, независимо от того, имеет ли объект допустимое значение типа T, базовые байты (1.7), составляющие объект, могут быть скопированы в массив из char или unsigned char. Если содержимое массива char или unsigned char будет скопировано обратно в объект, объект впоследствии сохранит свое первоначальное значение.

42) Используя, например, библиотечные функции (17.6.1.2) std::memcpy или std::memmove.

3 Для любого тривиальным Copyable типа T, если два указатели на T указывают на различных T объектов obj1 и obj2, где ни obj1, ни obj2 представляет собой базовый класс подобъектом, если основные байт (1.7), составляющие obj1 копируются до obj2, obj2 в дальнейшем будет содержать то же значение, что и obj1. [Пример: ...]

43) с использованием, например, функции библиотеки (17.6.1.2) std::memcpy или std::memmove.

Это, в принципе, позволяют назначение непосредственно s[2] если вы занять позицию, что назначение s[2] косвенно обязаны быть эквивалентна копированию всех какой-то другой Blob в массив, который как раз случается быть побайтно идентичны, за исключением для третьего байта, и скопируйте его в Blob: вы не назначаете s[0], s[1] и т. д. Для тривиально копируемых типов, включая char, что эквивалентно их точному значению, которое также не имеет наблюдаемых эффект.

Однако, если единственный способ получить s[2] == 'A' является манипуляцией памяти, то допустимый аргумент также может быть то, что вы копируете обратно в Blobэто не основные байты, которые составляли все предыдущие Blob , В этом случае технически поведение будет неопределенным бездействия.

Я действительно подозреваю, особенно с учетом того, «имеет ли объект допустимое значение типа T», что он предназначен для разрешения.

+0

Комментарии для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/101136/discussion-on-answer-by-hvd-pointer-arithmetics-on-non-array-types). –

0

Глава 3.10 стандарта, по-видимому, допускает этот конкретный случай, предполагая, что «доступ к сохраненному значению» означает «чтение или запись», что неясно.

3.10-10

Если программа пытается доступа сохраненного значения объекта через glvalue из других, чем один из следующих типов поведения недеформированного определено:

- (10.1) динамический тип объекта,

- (10.2) cv-qualified версия динамического типа объекта,

- (10.3) тип аналогично (как определенно в 4.4) для динамического типа объекта,

- (10.4) типа, который является знаком или без знака типа, соответствующего динамического типа объект,

- (10.5) типа, который подписанный или без знака типа, соответствующего CV-QUALI версии фи ред динамического типа объекта,

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

- (10.7) типа, который является (возможно, CV-Quali фи-й изд) базового класс типа динамического типа объекта,

- (10.8) a char или unsigned char type.

Смежные вопросы