Приведение / разыменование указателей на символы в двойной массив

0

Есть ли что-то не так, если вы производите двойной указатель на указатель char? Цель в следующем коде состоит в том, чтобы изменить один элемент тремя разными способами.

double   vec1[100];
double   *vp = vec1;
char     *yp = (char*) vp;
vp++;
vec1[1] = 19.0;
*vp = 12.0;
*((double*) (yp + (1*sizeof (vec1[0])))) = 34.0;
Теги:
pointers

2 ответа

0
Лучший ответ

Броски этого типа попадают в категорию "ОК, если вы знаете, что делаете, но опасны, если вы этого не сделаете".

Например, в этом случае вы уже знаете значение указателя "yp" (оно указывало на double), поэтому технически безопасно увеличивать его значение на величину double и повторно отбрасывать обратно в double*.

Контрпример: предположим, вы не знали, откуда пришел char* скажем, он был предоставлен вам как параметр функции. Теперь ваш бросок будет большой проблемой: поскольку char* технически выравнивается по 1 байт, а double обычно выравнивается по 8 байт, вы не можете быть уверены, что вам дали 8-байт-выровненный адрес. Если он выровнен, ваша арифметика приведет к действительному double*; если нет, то он будет разбит при разыменовании.

Это всего лишь один пример того, как отбрасывание может пойти не так. То, что вы делаете (на первый взгляд), похоже, что это сработает, но в целом вам действительно нужно обратить внимание, когда вы бросаете вещи.

  • 0
    Обратите внимание, что выравнивание не единственная вещь, которая делает двойной допустимым. Многие битовые комбинации не представляют действительные двойные числа ... и это также может генерировать прерывание в зависимости от настроек вашего FPU.
  • 0
    Это правда, но в этом случае он явно назначает действительные числа с плавающей запятой через каждый указатель.
0

С новыми процессорами INTEL основной проблемой, с которой вы можете столкнуться, является выравнивание. Скажите, что вы должны написать что-то вроде этого:

*((double*) (yp + 4)) = 34.0;

Тогда вы, вероятно, будете иметь ошибку времени выполнения, потому что double должен быть выровнен по 8 байтам. Это также верно для процессоров, таких как 68k или MIPS.

Это похоже на структуру и выполнение бросков по этой структуре. Вы вряд ли сломаете вещи.

В большинстве случаев, если вы можете этого избежать, ваш код будет намного сильнее. Лично я даже не использую такие приведения при чтении файла. Вместо этого я получаю данные из файла и помещаю их в структуру по мере необходимости. Скажем, я прочитал 4 байта в буфере для преобразования в целое число, я бы написал что-то вроде этого:

unsigned char buf[4];
...
fread(buf, 1, 4, f);
my_struct.integer = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);

Теперь я не сделал уродливого броска, и я мог контролировать конечную цель целого в файле, независимо от того, какой конечный элемент процессора вы используете.

  • 0
    Это не соответствует коду OP - OP использует sizeof отдельных элементов, поэтому проблем с выравниванием не возникает.
  • 0
    Зачем вам нужно использовать указатель char* если у вас под vec1 массив vec1 ? Мне кажется странным, что он использовал sizeof(vec1[0]) вместо sizeof(double) но не нашел его релевантным моему ответу.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню