Почему этот код вызывает ошибку на 64-битной архитектуре, но работает нормально на 32-битной?

Я столкнулся со следующей загадкой C:

Q: Почему следующая программа segfault на IA-64, но нормально работает на IA-32?

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }

Я знаю что размер int на 64-битной машине может не совпадать с размером указателя (int может быть 32 бита, а указатель может быть 64 бита). Но я не уверен, как это относится к вышеуказанной программе. Есть идеи?

3 ответа

Решение

Актерский состав int* маскирует тот факт, что без надлежащего #include тип возврата malloc предполагается, что int, У IA-64 случается sizeof(int) < sizeof(int*) что делает эту проблему очевидной.

(Обратите также внимание, что из-за неопределенного поведения он все еще может давать сбой даже на платформе, где sizeof(int)==sizeof(int*) верно, например, если соглашение о вызовах использовало разные регистры для возврата указателей, чем целые числа)

В FAQ к comp.lang.c есть запись, в которой обсуждается причина возврата malloc никогда не нужен и потенциально плох.

Скорее всего, потому что вы не включаете заголовочный файл для malloc и хотя компилятор обычно предупреждает вас об этом, тот факт, что вы явно приводите возвращаемое значение, означает, что вы говорите ему, что знаете, что делаете.

Это означает, что компилятор ожидает int быть возвращенным из malloc который затем бросает указатель. Если они разных размеров, это вызовет у вас горе.

Вот почему вы никогда не разыгрываете malloc вернуть в с. void* то, что он возвращает, будет неявно преобразован в указатель правильного типа (если только вы не включили заголовок, в этом случае он, вероятно, предупредил бы вас о потенциально небезопасном преобразовании типа int-указатель).

Вот почему вы никогда не будете компилировать без предупреждения о пропущенных прототипах.

Вот почему вы никогда не разыгрываете возврат malloc в C.

Приведение необходимо для совместимости с C++. Существует небольшая причина (читай: здесь нет причин), чтобы пропустить это.

Совместимость с С ++ не всегда необходима, а в некоторых случаях вообще невозможна, но в большинстве случаев ее очень легко достичь.

Другие вопросы по тегам