Ответ 1
Оба эти компилируются для меня. Первая ошибка распространена, когда вы забываете #include <stdlib.h>
до использования функций, объявленных внутри упомянутых (таких как malloc(size_t)
), что я и не забыл сделать.
C имеет некоторое интересное поведение во время компиляции, в том числе возможность вызывать функцию, которая никогда не просматривалась (ни определение прототипа, ни реализация). Когда встречается такой вызов, C предполагает, что функция:
- Что-то, что возвращает
int
- Принимает неизвестное количество аргументов, поэтому вызывающий может передать все, что захочет (включая неправильные вещи).
Напр., функция неявно предполагается, что она имеет вид:
int func();
Часто вы даже не заметите, за исключением предупреждений от вашего компилятора, которые сообщают о чем-то:
Warning: implicit declaration of `func` assumed to return `int`
и если вы находитесь на шаре, у вас есть уровни предупреждений, с включенными предупреждениями-как-то и поймать это.
Но что, если вы этого не сделаете? И что, если "вещь", возвращаемая функцией, не может быть представлена содержимым размером данных в реализации int
? Что, если, например, int
были 32-битными, но указатели данных были 64-битными? Например, допустим, что char *get_str()
объявлен в некотором заголовочном файле, который вы не включаете, и реализован в файле .c, который вы компилируете и связываете с вашей программой, который выглядит следующим образом:
#include <stdio.h>
// Note: NO prototype for get_str
int main()
{
char *s = get_str();
printf("String: %s\n", s);
return 0;
}
Ну, компилятор должен помнить, что int
и char*
несовместимы (вскоре после того, как он предупреждает, что get_str
предполагается возвращать int
). Но что, если вы вынуждаете руку компилятора, сообщая ему, чтобы сделать char*
так или иначе:
#include <stdio.h>
// Note: NO prototype for get_str
int main()
{
char *s = (char*)get_str(); // NOTE: added cast
printf("String: %s\n", s);
return 0;
}
Теперь, без предупреждения-as-errors, вы получите предупреждение о неявном объявлении, и вот оно. Код будет скомпилирован. Но будет ли он работать? Если sizeof(int)
!= sizeof(char*)
, (32-разрядный и 64-разрядный), скорее всего, не будет. Значение, возвращаемое из get_str
, - это 64-разрядный указатель, но вызывающий объект принимает только 32-битные данные, а затем приводит к 64-разрядному указателю. Короче говоря, приведение скрыло ошибку и открыло окно pandora из поведения undefined.
Итак, как все это относится к вашему коду? Не включая <stdlib.h>
, компилятор не знает, что такое malloc
. Поэтому он предполагает, что он имеет вид:
int malloc();
Затем, выведя результат в (int**)
, вы сообщаете компилятору, "что бы ни случилось, сделайте его int**
". При времени ссылки _malloc
найден (без сигнатуры параметра с помощью манипуляции с именем, например С++), подключен, и ваша программа готова к участию. Но на вашей платформе int
и указатели данных не имеют одинакового размера, поэтому вы оказываете несколько нежелательных последствий:
- Литой скрывается реальная ошибка.
- Поддельный указатель производится из половины бит реального возвращенного указателя.
- Как жестокая доза соли ране, выделенная память просачивается, так как нет действительных указателей где-нибудь, ссылающихся на нее (вы просто уничтожили единственную, оставив только половину ее).
- Вероятно, наиболее нежелательно, код будет демонстрировать нормальное поведение, если он скомпилирован в реализации, где
sizeof(int) == sizeof(int**)
.
Итак, вы создаете это на своем 32-битном поле Debian, все выглядит хорошо. Вы включаете свою домашнюю работу к профессору, который строит его на своем 64-битном Mac, и он падает, вы не выполняете задание, не сдаете класс, выходите из колледжа и проводите следующие десять лет, лаская кошку во время просмотра повторных попыток Seinfeld в подвале вашей мамы интересно, что пошло не так. Уч.
Не обрабатывайте отливку как серебряную пулю. Это не так. В C он нужен гораздо реже, чем люди его используют, и если он используется не в том месте, он может скрыть катастрофические ошибки. Если вы найдете точку в своем коде, где что-то не будет компилироваться без жесткого приведения, посмотрите еще раз. Если вы не абсолютно уверены в том, что актеры правильны, вероятность того, что это не так.
В этом случае он скрыл реальную ошибку, которую вы пренебрегли предоставлением компилятору достаточной информации, чтобы знать, что действительно делает malloc
.