Тип каламбура с void * без нарушения строгого правила сглаживания в C99

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

Я знаю, что это нарушает правило:

int x = 0xDEADBEEF;

short *y = (short *)&x;
*y = 42;

int z = x;

и я знаю, что могу безопасно использовать союз в C99 для каламбуров:

union{
    int x;
    short y;
} data;

data.x = 0xDEADBEEF;
data.y = 42;

int z = data.x;

но как я использую void * безопасно выполнить тип-каламбур в C99? Правильно ли следующее:

int x = 0xDEADBEEF;

void * helper = (void *)&x;

short *y = (short *)helper;
*y = 42;

int z = x;

Я подозреваю, что код все равно ломают строгое правило сглаживания, так как память при переменной xадрес может быть изменен обоими x и разыменован y.

если тип-каламбур не определен через void *, какова цель void * в C99?

1 ответов


void * не имеет ничего общего с Type-punning. Его основными целями являются:

  1. для обеспечения универсального распределения и освобождения операций, которые не заботятся о типе объекта, вызывающий объект хранит там (например,malloc и free).

  2. чтобы позволить вызывающему абоненту передать указатель на произвольный тип через функцию, которая передаст его обратно через обратный вызов (например,qsort и pthread_create). В этом случае компилятор не может применять тип проверки; это ваши обязанности при записи вызывающего абонента и обратного вызова убедитесь, что обратный вызов обращается к объекту с правильным типом.

указатели void также используется в нескольких местах (например,memcpy), которые на самом деле работают на объекте как наложенные unsigned char [] представление объекта. Это можно рассматривать как каламбур типа, но это не нарушение сглаживания, потому что char типы разрешены для псевдонима что-либо для доступа к его представление. В этом случае unsigned char * также будет работать, но void * имеет то преимущество, что указатели автоматически конвертировать в void *.

в вашем примере, так как оригинальный типа int и не союз, нет законного способа ввести каламбур и получить к нему доступ как short. Вместо этого вы можете скопировать значение x в объединение, выполните четко определенный тип-каламбур там, а затем скопируйте его обратно. Хороший компилятор должен полностью опустить копию. Кроме того, вы можете разбить запись в char пишет, а затем это будет юридическое псевдонимы.