Не нарушает ли перемещение значений одного типа с другим типом строгое совмещение имен? - PullRequest
2 голосов
/ 18 декабря 2009

Нарушает ли оно строгие правила псевдонимов, чтобы перемещать элементы любого типа с помощью 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. Мой вопрос посвящен тому, нарушает ли это строгий псевдоним или нет.

Ответы [ 2 ]

4 голосов
/ 18 декабря 2009

Первый цикл действительно технически нарушает строгое псевдонимы - он обращается к 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 возвращает их, в порядке.

1 голос
/ 18 декабря 2009

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

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

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

...