Программа, с которой я работаю, требует для запуска вторичного исполняемого файла (для сжатия ресурсов). По причинам обработки ошибок мне нужно возвращаемое значение дочернего процесса. Согласно справочной странице system
,
Если все системные вызовы завершаются успешно, возвращаемым значением является статус завершения дочерней оболочки, используемой для выполнения команды. (Состояние завершения оболочки — это состояние завершения последней выполненной ею команды.)
В соответствии с этим, состояние возврата моего вызова system
должно быть возвращаемым значением вызванного процесса. Но, похоже, это не так. Вместо этого, когда Генератор возвращает EXIT_FAILURE
, программа получает EXIT_SUCCESS
или 0
. Я что-то неправильно понимаю?
Мой код ниже.
// Checks to see if the generator still exists using access().
bool asset_generator_availability = CheckAssetGenerator();
if (!asset_generator_availability) LogMessage("Assets already generated.");
else
{
LogWarning(
"Assets still uncompressed and unformatted. Running the Generator.");
u8 generator_state = system("./AssetGenerator && rm AssetGenerator");
// Here is the problem line.
if (generator_state == EXIT_FAILURE) exit(EXIT_FAILURE);
}
@tofro Ах, ладно. Но как можно использовать эти функции?
«Код выхода» ошибочно относится как к значению, возвращаемому main
, так и к целому числу, возвращаемому wait
, которое содержит это значение, но сдвинуто. В данном случае речь идет о последнем. Используйте макросы из wait's docs.
@ikegami Справочная страница waitpid
пролила очень мало света на то, что делает любая из этих функций. Есть ли дополнительная ссылка, которую я должен увидеть?
Обновлено ссылкой, которая четко документирует макросы (а не функции).
Эта проблема возникает потому, что когда система успешно запускает вызванный процесс, она не возвращает прямое возвращаемое значение запущенного процесса. Вместо этого он возвращает «статус ожидания», который можно проверить с помощью макроса, описанного в waitpid(2). (т. е. WIFEXITED(), WEXITSTATUS() и т. д.). На страницах руководства есть более подробная информация по этому вопросу, но для вашего кода вы можете использовать WIFEXITED и WEXITSTATUS следующим образом:
if (WIFEXITED(generator_state) && WEXITSTATUS(generator_state) == EXIT_FAILURE)
{
exit(EXIT_FAILURE);
}
В этом коде WIFEXITED проверяет, что дочерний процесс завершился нормально, а WEXITSTATUS проверяет статус выхода дочернего процесса. Однако system
также предоставляет другие возвращаемые значения, если команда имеет значение NULL, дочерний процесс не может быть создан или его статус не может быть получен, оболочка не может быть выполнена в дочернем процессе. Чтобы учесть это, вы можете использовать несколько других макросов waitpid следующим образом:
if (generator_state == -1)
{
exit(EXIT FAILURE);
} //exits if system fails to create the child process or retrieve it's status.
else
{
if (WIFEXITED(generator_state))
{
int exit_status = WEXITSTATUS(generator_state);
if (exit_status == EXIT_FAILURE)
{
exit(EXIT_FAILURE);
} //exits on the failure in the child code. You could add other failures in the same way.
else
{
//Handle successful completion of the asset generator.
}
}
else if (WIFSIGNALED(generator_state))
{
int signum = WTERMSIG(generator_state);
LogError("Asset Generator was terminated by signal: %d", signum);
exit(EXIT_FAILURE);
}// Logs if the generator is terminated by a signal, and the signal number.
else
{
if (WEXITSTATUS(generator_state) == 127)
{
LogError("Failed to execute shell in child process.");
} //Logs if the shell couldn't be executed in the child process.
else
{
LogError("Asset Generator terminated abnormally.");
exit(EXIT_FAILURE);
}// Logs if the generator is terminated in some other unexpected way.
}
}
Ради примера я использовал функцию LogError для отдельных ошибок, так как видел, что в предыдущем коде у вас было LogWarning. Если у вас нет функции LogError, вы можете создать ее или использовать какой-либо другой метод для учета отдельных ошибок. .
Надеюсь это поможет!
Обновлено: Ниже приведены страницы руководства для system
и wait
.
https://man7.org/linux/man-pages/man3/system.3.htmlhttps://man7.org/linux/man-pages/man2/waitpid.2.html
Это решение, похоже, ничего не изменило. Стоит ли мне также изменить оформление моего звонка system
?
Неважно, проблема возникла из-за приведения типа u8
из результата system
вызова i32
. Это сработало безупречно. Спасибо!
@Zenais system
возвращает int
, а не u8
или i32
@ikegami i32 (32-битное целое число со знаком) — это то, что system
возвращает, насколько мне известно. Нет?
@Zenais, Нет. Опять же, он возвращает int
, а не i32
.
@ikegami Согласно gnu.org/software/gnu-c-manual/…, «int — 32-битный тип данных int может содержать целочисленные значения в диапазоне от -2 147 483 648 до 2 147 483 647. Вы также можете обратиться к этот тип данных как подписанный int или подписанный». i32
— это просто мои внутренние определения типов для int32_t.
@Zenais, int
не гарантированно будет 32-битным. Это гарантированно будет только 16 бит. И он может быть на любой размер больше. Использование int32_t
неправильно. system
возвращает int
. /// Также сомнительна практика запутывания использования стандартных и известных int32_t
.
@Anon520 Anon520, вряд ли твое решение будет правильным. Другие коды ошибок, кроме 1
, он не считает ошибками, хотя так и должно быть. Он не считает убийство ребенка по сигналу ошибкой, хотя так и должно быть. (Да, ОП тоже допустил эти ошибки, но это вас не оправдывает.)
@ikegami справедливая точка зрения. Я обновил ответ, чтобы иметь возможность обрабатывать многие другие возвращаемые значения, предоставляемые системой, а также любые другие неожиданные ошибки.
Вы слишком рано перестали читать справочную страницу: в последних двух случаях возвращаемое значение представляет собой «статус ожидания», который можно проверить с помощью макросов, описанных в waitpid(2). (т. е. WIFEXITED(), WEXITSTATUS() и т. д.).