Вы не можете принудительно выполнить проверку
Я не думаю, что есть способ сделать это так, как вы этого хотите. В конце концов, в операторе printf("%d",fun ())
вы на самом деле проверяете возвращаемое значение из fun()
, отправляя его в другую функцию. Конечно, printf
на самом деле не «проверяет» возвращаемое значение, но вы могли бы использовать его следующим образом:
void exit_if_fun_returns_negative_value(int val) { if(val<0) exit(EXIT_FAILURE); }
int main(void)
{
exit_if_fun_returns_negative_value(fun());
}
Но нет никакого способа заставить компилятор понять разницу между этим иваше printf
заявление. Я предполагаю, что вы хотите заставить программиста сохранить возвращаемое значение в переменной, но я не знаю, как это сделать, и даже если вы могли бы это сделать, это не гарантирует надлежащей проверки. Просто посмотрите на этот пример:
char *array;
void *ptr;
ptr = realloc(array, 20);
strcpy(array, "Hello, World!");
Обратите внимание, как мы сохраняем возвращаемое значение в ptr
, но поскольку мы не делаем что-то вроде if(ptr == NULL) exit(EXIT_FAILURE);
, это довольно бессмысленно.
НоВы можете запретить полное игнорирование возвращаемого значения
Однако есть способ предотвратить операторы, в которых вы не используете (что, конечно, не то же самое, что проверка на самом деле) возвратазначение на всех.
Насколько я знаю, нет портативного способа сделать это. Вам придется полагаться на расширения компилятора. Gcc имеет такое расширение.
__attribute__ ((warn_unused_result)) int foo (void)
{
return 5;
}
int main(void)
{
foo();
}
Компиляция этого сгенерирует это предупреждение:
$ gcc main.c
main.c: In function ‘main’:
main.c:9:5: warning: ignoring return value of ‘foo’, declared with attribute warn_unused_result [-Wunused-result]
9 | foo();
| ^~~~~
Для того, чтобы рассматривать это как ошибку, скомпилируйте с -Werror
$ gcc main.c -Werror
main.c: In function ‘main’:
main.c:9:5: error: ignoring return value of ‘foo’, declared with attribute warn_unused_result [-Werror=unused-result]
9 | foo();
| ^~~~~
cc1: all warnings being treated as errors
Если вы хотите, чтобы все остальные предупреждения были просто предупреждениями, скомпилируйте с -Werror=unused-result
. Пример:
$ cat main.c
__attribute__ ((warn_unused_result))
int foo (void)
{
return 5;
}
int main(void)
{
int *x = 5;
foo();
}
$ gcc main.c -Werror=unused-result
main.c: In function ‘main’:
main.c:9:14: warning: initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
9 | int *x = 5;
| ^
main.c:10:5: error: ignoring return value of ‘foo’, declared with attribute warn_unused_result [-Werror=unused-result]
10 | foo();
| ^~~~~
cc1: some warnings being treated as errors
Измените сигнатуру, включив в нее выходной параметр
Один из вариантов для достижения чего-то похожего - перенести возвращаемое значение в параметр. Это заставит сохранить «возвращаемое значение» в параметре, и вы не сможете вызвать функцию, не отправив ей выходную переменную. Измените
int fun (){ return 3;}
на
void fun(int *ret) { *ret=3; }
Но, как я уже упоминал выше, я не могу понять, как вы можете принудительно проверить переменную. Это только принудительно назначает.
Функции оболочки
Другой вариант - использовать функции оболочки. Это часто значительно снижает гибкость, поэтому подумайте дважды, прежде чем использовать его, но это вариант, который может быть полезен в некоторых случаях. Допустим, у вас есть пара заголовок / источник. Поместите прототип оболочки в файл заголовка, а реализацию как оболочки, так и функции - в исходный файл. Это скроет оригинальную функцию от программиста. Это может выглядеть так:
.h
int fun_wrapper();
.c
int fun() { return 3; }
int fun_wrapper()
{
int ret = fun();
if(ret<0) exit(EXIT_FAILURE);
return ret;
}
Как использовать эту технику для библиотечных функций
Я создалсвязанный вопрос, у которого есть ответ. Речь идет о том, как использовать это для fgets
и других функций из библиотеки: Как создать оболочки для функций библиотеки с оригинальным именем?