Небезопасное преобразование

Действительно ли следующее преобразование безопасно?

int b[10][10];
char *x;
int a[]={0,1,2,3,4,5,6,7,8,9};

for(int i=0;i<10;i++)
  for(int j=0;j<10;j++)
    b[i][j]=a[i];

for(x=(char *)&b[0];x<=(char *)&b[9][9];x+=sizeof(a+1)) // Problem lies here!
    printf("%d\n",*x);

Я не думаю вышеупомянутое преобразование в for цикл безопасен (я думаю, что это - зависимый платформы). Исправьте меня, если я неправ. Я удивлен, потому что код компилирует, не давая предупреждений, даже когда скомпилировано с помощью -Wall -pedantic опции в gcc.

5
задан Prasoon Saurav 6 February 2010 в 13:23
поделиться

2 ответа

Все это имеет шанс быть законным по одной и только одной причине: объект массива 2D int интерпретируется как массив из char объектов. В то время как в общем случае переинтерпретация памяти приводит к неопределенному поведению, спецификация языка явно разрешает переинтерпретации "массив [подписанных / беззнаковых] символов" для объектов любого типа.

Однако одна формальная проблема безопасности все еще существует. Язык не гарантирует, что какой-либо битовый шаблон является допустимым значением типа char . Ваша попытка прочитать переинтерпретируемую память с помощью типа char теоретически может вызвать неопределенное поведение, если она встречает представление прерывания для char . В целях безопасности вы должны использовать тип unsigned char , который является единственным типом, не имеющим представления прерывания. Конечно, платформу с треппингом char смело можно назвать «экзотической».

Между тем, ваш sizeof (a + 1) , похоже, не имеет никакого смысла. a + 1 является выражением типа int * . Почему вы хотите использовать размер указателя для увеличения значения x в этом случае, мне не ясно. Чего вы пытались достичь?

Что касается отсутствия предупреждений ... Я не ожидал, что компилятор выдаст здесь какие-либо предупреждения. GCC часто предупреждает о каламбурах типов (также известных как переинтерпретация памяти), но поскольку переинтерпретации char явно разрешены (как я сказал выше), здесь нет предупреждения. Более того, явное приведение типов обычно подавляет любые предупреждения, поскольку они являются способом сообщить компилятору, что вы действительно хотите что-то сделать, независимо от того, насколько это неправильно и / или опасно.

7
ответ дан 14 December 2019 в 04:37
поделиться

приведение любого типа указателя к char * явно разрешено языком C. так что в большинстве случаев это нормально.

for(x=(char *)&b[0]; x <= (char *)&b[9][9]; x += sizeof(a+1))  

Первая часть в порядке x = (char *) & b [0]; устанавливает указатель char на начало массива. Тест также хорош x <= (char *) & b [9] [9] будет истинным, пока x точек внутри массива.

x + = sizeof (a + 1) - сомнительная часть. На большинстве 32-битных архитектур ЦП sizeof (int *) просто бывает таким же, как sizeof (int), поэтому этот код, вероятно, будет работать , но только случайно.

Я уверен, что предполагалось x + = sizeof (a [0]) или x + = sizeof (b [0]) , но поскольку код на самом деле сделал то, что задумал, бага никто не заметил.

1
ответ дан 14 December 2019 в 04:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: