История изменений
Исправление 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;
}