Это UB для доступа к «дополненным» байтам?

Если у меня есть такой объект:

struct {
uint32_t n;
uint8_t c;
} blob {};

тогда будет 3 дополненных байта.

Это UB для доступа к дополненным байтам? Например:

uint8_t * data = reinterpret_cast<uint8_t*>(&blob);
std::cout << data[4] << data[5] << data[6] << data[7];

Сначала я предположил, что это, вероятно, UB, но если это правда, то memcpy также будет UB:

memcpy(buf, &blob, sizeof(blob));

Мои конкретные вопросы:

  • Это UB для доступа к дополненным байтам?
  • Если нет, значит ли это, что значения также определены?

10

Решение

Нет, это не UB для доступа к заполнению, когда весь объект был инициализирован нулем (стандарт говорит в §8.5 / 5, что заполнение инициализируется в 0 битов, когда объекты инициализируются нулями) или инициализируется значением, и это не класс с определяемым пользователем конструктором.

6

Другие решения

Я думаю, при правильных обстоятельствах, вы могли бы в конечном итоге с UB для этого. Я думаю о том, где у вас есть память с проверкой ECC или Parity, где биты ecc / parity устанавливаются путем записи в память. Если блок памяти ранее не использовался [никогда не записывался в ВСЕ], и вы читали неинициализированные байты в поле заполнения, это может привести к ошибке ecc / parity, когда память, которая никогда не была записана читается

Конечно, в такой системе вы могли бы избежать целой кучи боли, просто выполняя «заполнение всей памяти» в какой-то момент во время загрузки, так как это было бы просто так:

struct Blob
{
uint32_t n;
uint8_t c;
};

Blob *b = malloc(sizeof(Blob)*10);

for(int i = 0; i < 10; i++)
{
b[i].n = i;
b[i].c = i;
}...

Blob a[3];

memcpy(a, &b[1], sizeof(a));    // Copies 3 * Blob objects, including padding.

Теперь, поскольку не все биты b [x] были установлены, возможно, не удастся скопировать данные в memcpy из-за ошибок четности / ecc. Это было бы очень плохо. Но в то же время компилятор нельзя принудительно «устанавливать» все области заполнения.

Я пришел к выводу, что это UB, но вряд ли это вызовет проблемы, если нет особых обстоятельств. Конечно, вы увидите вышеупомянутый тип memcpy код в большом количестве кода.

0

Если это не неопределенное поведение, оно определенно зависит от реализации. В то время как стандарт C ++ не гарантирует многое о том, что делает ваша программа, спецификация ABI вашей системы — SysV если вы используете Linux — будет. Я подозреваю, что если вы возитесь с битами заполнения, вы, вероятно, больше интересуетесь тем, как ваша программа будет вести себя в вашей системе, чем тем, как она будет вести себя в любой произвольной C ++ — соответствующей системе.

0

Структура POD будет жить в непрерывном блоке памяти размером не менее sizeof (struct) байтов (который включает в себя любые байты заполнения). Доступ к дополнительным байтам (если они существуют) будет UB, только если он не был инициализирован.

memset(&s, 0, sizeof(s));

Это инициализирует все байты, включая заполнение. После чего чтение с отступа не будет UB.

Конечно, memset() такое C-ism, и мы бы никогда не сделали этого на C ++, верно?

0

В Си это не неопределенное поведение. Единственный раз, когда вы получаете неопределенное поведение при доступе к неинициализированным вещам (таким как заполнение в объектах), это когда у объекта есть автоматическая продолжительность хранения и НИКОГДА НЕ БЫЛ ЕГО АДРЕС:

6.3.2.1.2:
Если
lvalue обозначает объект автоматической длительности хранения, который мог быть
объявлено с классом хранения регистра (никогда не был взят его адрес), и этот объект
неинициализирован (не объявлен инициализатором, и присвоение ему не было
выполняется до использования), поведение не определено.

Но в этом случае вы берете адрес (с &), поэтому поведение четко определено (ошибки не возникает), но вы можете получить любое случайное значение.

В C ++ все ставки отключены, как это обычно бывает.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector