Нарушает ли перемещение значений одного типа в другой тип строгий псевдоним?

StackOverflow https://stackoverflow.com/questions/1926282

  •  20-09-2019
  •  | 
  •  

Вопрос

Нарушает ли строгие правила псевдонимов перемещение элементов любого типа с помощью uint32_t, а затем их обратное чтение?Если да, то нарушает ли это также строгие правила псевдонимов для memcpy из массива uint32_ts в массив любого типа, а затем считывает элементы обратно?

Следующий пример кода демонстрирует оба случая:

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

int main(void) {
    const char *strings[5] = {
        "zero", "one", "two", "three", "four"
    };
    uint32_t buffer[5];
    int i;

    assert(sizeof(const char*) == sizeof(uint32_t));

    memcpy(buffer, strings, sizeof(buffer));

    //twiddle with the buffer a bit
    buffer[0] = buffer[3];
    buffer[2] = buffer[4];
    buffer[3] = buffer[1];

    //Does this violate strict aliasing?
    const char **buffer_cc = (const char**)buffer;
    printf("Test 1:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", buffer_cc[i]);
    printf("\n");

    //How about this?
    memcpy(strings, buffer, sizeof(strings));
    printf("Test 2:\n");
    for (i=0; i<5; i++)
        printf("\t%s ", strings[i]);
    printf("\n");

    return 0;
}

Пожалуйста, не обращайте внимания на мое предположение о 32-битной платформе.Кроме того, если размеры элементов не совпадают с размером uint32_t, я знаю, что нужно дополнить их и скопировать правильное количество uint32_t.Мой вопрос сосредоточен на том, нарушает ли это строгий псевдоним.

Это было полезно?

Решение

Первый цикл делает технически нарушает строгий псевдоним — он получает доступ uint32_t объекты через lvalue типа char *.Однако трудно представить, как какой-либо оптимизатор может вызвать проблемы в этом конкретном случае.Если вы немного изменили его, чтобы сделать что-то вроде:

printf("\t%s ", buffer_cc[0]);
buffer[0] = buffer[3];
printf("\t%s ", buffer_cc[0]);

Ты мощь увидеть одну и ту же строку, напечатанную дважды, поскольку оптимизатор будет иметь право только загружать buffer_cc[0] в регистр один раз, потому что вторая строка изменяет только объект типа uint32_t.

Второй цикл, который memcpyЕсли они вернутся, все в порядке.

Другие советы

buffer_cc[0] и strings[3] (например) являются указателями, которые ссылаются на одну и ту же ячейку памяти, но имеют один и тот же тип, поэтому не нарушают строгий псевдоним. buffer[0] не является указателем, поэтому не нарушает строгий псевдоним.Оптимизация псевдонимов возникает при разыменовании указателей, поэтому я не ожидал бы, что это вызовет проблемы.

Как вы намекаете в коде и последнем абзаце вашего вопроса, настоящая проблема в примере кода возникает, когда указатели и uint32_t имеют разные размеры.

Кроме того, вы всегда можете использовать псевдоним char* указать на другой тип, не нарушая строгий псевдоним, но не наоборот.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top