Как экспортировать обработку ошибок в функцию на C с помощью ‹errno.h›

Я проверяю, вводит ли пользователь правильный номер и тип аргументов cmd при вызове main.

Я подумал, что было бы неплохо написать функцию, которая выводит некоторый текст, чтобы я мог повторно использовать ее при проверке указателей NULL. Я включил <errno.h>.

void errcall()
{
  perror("Error printed by perror()");
  exit(EXIT_FAILURE);
}

Затем я написал функцию для проверки правильности и достаточности аргументов.

void err_cmd_handle(int argc_input)
{
  if(argc_input==1 || argc_input>2)
    errcall(); 
}

Когда я вызываю это в main, передавая int argc в качестве аргумента err_cmd_handle(), я получаю успех, даже если я не передал никаких аргументов, кроме запуска программы. Почему условие не проверяется правильно?

int main(int argc,char* argv[])
{
  err_cmd_handle(argc);
  return 0;
}

person Balázs Börcsök    schedule 19.11.2019    source источник
comment
Как вы думаете, почему errno может иметь полезное значение при вызове errcall?   -  person rici    schedule 19.11.2019
comment
Пожалуйста, приведите полный пример. Ваше объяснение того, что вы делаете в main(), и ваше, я думаю, это как-то связано с тем, что мои функции неявны, или мои переменные находятся в неправильной области видимости, делают то, что вы на самом деле делаете, очень неясным.   -  person Andrew Henle    schedule 19.11.2019
comment
@rici Насколько я знаю, для него устанавливается значение, когда передаются аргументы cmd пользовательских типов.   -  person Balázs Börcsök    schedule 19.11.2019
comment
Если вы получаете предупреждения о неявных функциях или о чем-либо еще - исправьте их прежде чем спрашивать о проблеме. Или, если вы считаете, что эти предупреждения уместны, включите их в вопрос!   -  person Clifford    schedule 19.11.2019
comment
Значит, вся эта обработка ошибок в errno.h бесполезна даже для проверки указателей? Я имею в виду, если файлы открыты?   -  person Balázs Börcsök    schedule 19.11.2019
comment
Я помогаю вам, пытаясь понять ваш вопрос. Однако я удалил свой комментарий, потому что увидел актуальность errcall() - не очевидно, что ваш вопрос касается важных вещей последним. Однако bee clear errno не имеет отношения к вашей задаче, но вопрос о том, почему он возвращает успех, остается в силе.   -  person Clifford    schedule 19.11.2019
comment
Эх, что бы я просто удалю пост, может быть, если я потрачу 50 часов на исследование этой темы, я пойму это. Все это хорошо для того, чтобы терять очки и выглядеть придурком.   -  person Balázs Börcsök    schedule 19.11.2019
comment
Если, например, стандартная библиотечная функция возвращает состояние ошибки (как задокументировано) и задокументировано, что она устанавливает errno, то можно проверить errno. Это не поддержка обработки ошибок общего назначения — она предназначена для сообщения об ошибках из стандартной библиотеки.   -  person Clifford    schedule 19.11.2019
comment
@BalázsBörcsök: Не делайте этого - наберитесь терпения, отвечайте на комментарии, улучшая вопрос - вы слишком чувствительны. В конечном счете, ваш вопрос не об ошибке, а о том, почему if(argc_input==1 || argc_input>2), по-видимому, терпит неудачу. На ваш вопрос нельзя ответить без дополнительной информации и расследования, потому что он неправдоподобен и, скорее всего, является ошибкой наблюдения.   -  person Clifford    schedule 19.11.2019
comment
Итак, errno устанавливается после каждого вызова функции?   -  person Balázs Börcsök    schedule 19.11.2019
comment
Нет - после вызовов функций, в которых явно указано, что они установили это в своей документации - не все вызовы функций. Однако это не по теме - вы не спрашивали об ошибке - просто говорили об этом - возможно, было бы лучше, если бы вы этого не делали и упростили вопрос до просто выхода-успеха, выхода-ошибки и отдельно спросили о проверке командной строки аргументы.   -  person Clifford    schedule 19.11.2019
comment
Мне кажется, что вы прекрасно поняли, в чем была моя проблема. Трудно задать правильный вопрос, если я постукиваю в темноте.   -  person Balázs Börcsök    schedule 19.11.2019
comment
Это ошибка наблюдения - я отправлю ответ сейчас, когда разобрался - слишком долго для комментария. Вы должны были включить вывод вашей программы - тогда было бы совершенно очевидно, что происходит.   -  person Clifford    schedule 19.11.2019
comment
Вы не добились успеха, а получили ошибку и напечатали успех. Просто как тот. В будущем опубликуйте все: ввод, фактический вывод, ожидаемый вывод, код (полный, а не фрагменты) и, если есть проблемы со сборкой, журнал сборки. Учтите, что контрольный список для хорошего вопроса и вы получите гораздо меньше проблем в будущем. Даже вопросы новичка могут набрать больше голосов только за то, что они хорошо сформулированы. Будьте настойчивы.   -  person Clifford    schedule 19.11.2019


Ответы (2)


Если вы возьмете свой полный код с необходимыми заголовками:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

void errcall()
{
  perror("Error printed by perror()");
  exit(EXIT_FAILURE);
}
void err_cmd_handle(int argc_input)
{
  if(argc_input==1 || argc_input>2)errcall(); 
}

int main(int argc,char* argv[])
{
    err_cmd_handle(argc);
    return 0;
}

а затем запустите его без аргументов, вывод:

Error printed by perror(): Success 

Очевидно, что проверка сработала, потому что был вызван errcall(). Текст "Успех" просто потому, что значение errno равно нулю - потому что его ничего не устанавливало.

Ваш исходный код до того, как вы изменили вопрос, имел:

if(argc_input==1 || argc_input>2)errcall();
  else exit(EXIT_SUCCESS); 

Итак, когда вы заявили:

тогда я получаю успех, даже когда я не приводил никаких аргументов, кроме запуска программы

Разумно было предположить, что он оканчивался через exit(EXIT_SUCCESS); — это явно не так. Кроме того, я изначально предположил, что errno не имеет ничего общего с вопросом, потому что казалось, что errcall() нельзя было вызвать, если он вернул EXIT_SUCCESS. Надеюсь, вы понимаете, почему ваш вопрос вызвал столько путаницы и комментариев?

person Clifford    schedule 19.11.2019
comment
Также обратите внимание, что вызовы функций могут изменять errno. Согласно 7.5 Ошибки errno.h›, стр. 3 : значение errno может быть установлено ненулевым при вызове библиотечной функции независимо от наличия ошибки, при условии, что использование errno не задокументировано в описании функции в этом международном стандарте. Я также почти уверен, что видел стандартные функции, которые документируют использование errno, изменяя его значение, когда ошибки не было, поэтому значение errno действительно полезно только сразу после сбоя функции. - person Andrew Henle; 19.11.2019
comment
@AndrewHenle Я думаю, что ваш комментарий неуместен. Это не имеет отношения к этому ответу. Возможно, вы обращались к комментариям, размещенным к самому вопросу. Ранее в этом разговоре я четко заявил, что errno указывает на ошибку только тогда, когда функция, которая его устанавливает, возвращает состояние ошибки. - person Clifford; 19.11.2019
comment
@BalázsBörcsök учтите это, вы решили, что argc_input==1 || argc_input>2 является условием ошибки, perrno() не волшебным образом знает, как напечатать ошибку, он просто отображает определенные известные стандартные значения ошибка как текст. Вы можете установить errno самостоятельно, но на самом деле это было предназначено для системных ошибок, а не для ошибок уровня приложения, где вы могли выводить более полезную и актуальную информацию, такую ​​как справка/руководство по командной строке. - person Clifford; 19.11.2019

Errno не был установлен.

void errcall()
{
  printf("Value of errno: %d\n", errno);
  printf("Error: %s\n",strerror(errno));
  perror("Error printed by perror()");
  exit(EXIT_FAILURE);
}

int main(int argc,char* argv[])
{
    if(argc!=2) 
    {
       errno=EINVAL;
       errcall();
    }

    return 0;
}
person Mike Seeds    schedule 19.11.2019