LINUX.ORG.RU

История изменений

Исправление gentoo_root, (текущая версия) :

Юзай union, бро

union не хочу юзать, потому что не хочу лишнего копирования. Мне это представляется как-то так:

char buf[1024];
/* recv'ом зафигачили в buf какие-то данные, опустим детали */
union {
    char buf[1024];
    struct payload payload;
} u;
memcpy(u.buf, buf, sizeof(u.buf));
struct payload *payload = &u.payload;

Во-первых, выглядит громоздко. Во-вторых, buf будет копироваться (бегло посмотрел ассемблерный код с -O3, там есть rep stos). В основном мне здесь не нравится копирование.

Почитал здесь цитаты из стандарта и сделал следующие выводы. Если выделять buf каким-нибудь malloc'ом, то можно смело сначала в него зафигачить кучу чаров, а потом скастовать указатель к struct payload * и работать с ним. Если же buf — это объявленная переменная, то у неё уже есть эффективный тип char, приведение к struct payload * будет нарушением правил алиасинга.

Поэтому нарушения алиасинга есть во всех примерах из ОП. Варнинги от gcc бесполезны, поскольку я нафигачил у себя локально кучу примеров, где на разных уровнях -Wstrict-aliasing= варнинги то есть, то нет, при этом нарушения есть. Есть даже пример, не выводящий никогда варнинг, но дающий неправильный ответ; clang ведёт себя так же:

#include <stdio.h>

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=3
// no warning

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=2
// no warning

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=1
// no warning

// strict aliasing is broken

struct global {
        int a;
} global;

int modify(char *test)
{
        global.a = 'a';
        *(short *)test = 'b';
        return global.a;
}

int main()
{
        printf("%c\n", modify((char *)&global));
        return 0;
}

Пример печатает a, запись символа b, скорее всего, переставляется.

Исходная версия gentoo_root, :

Юзай union, бро

union не хочу юзать, потому что не хочу лишнего копирования. Мне это представляется как-то так:

char buf[1024];
/* recv'ом зафигачили в buf какие-то данные, опустим детали */
union {
    char buf[1024];
    struct payload payload;
} u;
memcpy(u.buf, buf, sizeof(u.buf));
struct payload *payload = &u.payload;

Во-первых, выглядит громоздко. Во-вторых, buf будет копироваться (бегло посмотрел ассемблерный код с -O3, там есть rep stos). В основном мне здесь не нравится копирование.

Почитал здесь цитаты из стандарта и сделал следующие выводы. Если выделять buf каким-нибудь malloc'ом, то можно смело сначала в него зафигачить кучу чаров, а потом скастовать указатель к struct payload * и работать с ним. Если же buf — это объявленная переменная, то у неё уже есть эффективный тип char, приведение к struct payload * будет нарушением правил алиасинга.

Поэтому нарушения алиасинга есть во всех примерах из ОП. Варнинги от gcc бесполезны, поскольку я нафигачил у себя локально кучу примеров, где на разных уровнях -Wstrict-aliasing= варнинги то есть, то нет, при этом нарушения есть. Есть даже пример, не выводящий никогда варнинг, но дающий неправильный ответ; clang ведёт себя так же:

#include <stdio.h>

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=3
// no warning

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=2
// no warning

// gcc 5.c -o 5 -O3 -Wall -Wextra -Wstrict-aliasing=1
// no warning

// strict aliasing is broken

struct global {
        int a;
} global;

int modify(char *test)
{
        global.a = 'a';
        *(short *)test = 'b';
        return global.a;
}

int main()
{
        printf("%c\n", modify((char *)&global));
        return 0;
}