Я использовал следующую часть кода для чтения данных из файлов как часть большей программы.
double data_read(FILE *stream,int code) {
char data[8];
switch(code) {
case 0x08:
return (unsigned char)fgetc(stream);
case 0x09:
return (signed char)fgetc(stream);
case 0x0b:
data[1] = fgetc(stream);
data[0] = fgetc(stream);
return *(short*)data;
case 0x0c:
for(int i=3;i>=0;i--)
data[i] = fgetc(stream);
return *(int*)data;
case 0x0d:
for(int i=3;i>=0;i--)
data[i] = fgetc(stream);
return *(float*)data;
case 0x0e:
for(int i=7;i>=0;i--)
data[i] = fgetc(stream);
return *(double*)data;
}
die("data read failed");
return 1;
}
Теперь мне говорят использовать -O2
и я добираюсь после предупреждения gcc: warning: dereferencing type-punned pointer will break strict-aliasing rules
Googleing я нашел два ортогональных ответа:
по сравнению с
В конце я не хочу игнорировать предупреждения.Что Вы порекомендуете?
[обновление] я заменил игрушечным примером с реальной функцией.
Похоже, вы действительно хотите использовать fread:
int data;
fread(&data, sizeof(data), 1, stream);
Тем не менее, если вы действительно хотите чтобы пройти путь чтения символов, а затем переинтерпретировать их как int, безопасный способ сделать это в C (но не в C ++) - использовать объединение:
union
{
char theChars[4];
int theInt;
} myunion;
for(int i=0; i<4; i++)
myunion.theChars[i] = fgetc(stream);
return myunion.theInt;
Я не уверен, почему длина данных
в вашем исходном коде равна 3. Я предполагаю, что вам нужно 4 байта; по крайней мере, я не знаю ни одной системы, в которой int составляет 3 байта.
Обратите внимание, что и ваш код, и мой очень непереносимы.
Редактировать: Если вы хотите читать целые числа различной длины из файла в переносном режиме, попробуйте что-нибудь вроде этого:
unsigned result=0;
for(int i=0; i<4; i++)
result = (result << 8) | fgetc(stream);
(Примечание: в реальной программе вы бы дополнительно захотели проверить возвращаемое значение fgetc () на соответствие EOF.)
Читает 4-байтовый беззнаковый файл из файла в формате с прямым порядком байтов, независимо от порядка байтов в системе. Он должен работать практически в любой системе, где длина без знака составляет не менее 4 байтов.
Если вы хотите быть нейтральным к порядку байтов, не используйте указатели или объединения; вместо этого используйте битовые сдвиги.
Обычно вы можете прочитать сообщение gcc как парень, которого вы ищете, не говорите, что я вас не предупреждал .
Преобразование трехбайтового массива символов в int
- одна из худших вещей, которые я когда-либо видел. Обычно ваш int
имеет не менее 4 байтов. Итак, для четвертого (и, возможно, большего количества, если int
шире) вы получите случайные данные. И затем вы бросаете все это на дабл
.
Просто не делайте этого. Проблема сглаживания, о которой предупреждает gcc, невинна по сравнению с тем, что вы делаете.
Очевидно, стандарт позволяет sizeof (char *) отличаться от sizeof (int *), поэтому gcc жалуется, когда вы пытаетесь выполнить прямое приведение. void * немного особенный в том, что все может быть преобразовано туда и обратно в void * и обратно. На практике я не знаю многих архитектур / компиляторов, в которых указатель не всегда одинаков для всех типов, но gcc имеет право выдавать предупреждение, даже если оно раздражает.
Я думаю, что безопасным способом будет
int i, *p = &i;
char *q = (char*)&p[0];
или
char *q = (char*)(void*)p;
Вы также можете попробовать это и посмотреть, что вы получите:
char *q = reinterpret_cast<char*>(p);