Вопрос

Безопасно ли следующее преобразование?

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.

Это было полезно?

Решение

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

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

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

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

Другие советы

приведение любого типа указателя к 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]), но поскольку код действительно делал то, что было задумано, никто не заметил ошибки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top