На Unicies, или где-нибудь еще у вас есть execve
и он работает как the man page specifies, вы можете просто ... убить меня за использование atoi
, потому что это вообще ужасно, для такого рода исключением случая.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char** argv) {
(void) argc;
printf("arg: %s\n", argv[1]);
int count = atoi(argv[1]);
if (getchar() == 'y') {
++count;
char buf[20];
sprintf(buf, "%d", count);
char* newargv[3];
newargv[0] = argv[0];
newargv[1] = buf;
newargv[2] = NULL;
execve(argv[0], newargv, NULL);
}
return count;
}
Пример:
$ ./res 1
arg: 1
y
arg: 2
y
arg: 3
y
arg: 4
y
arg: 5
y
arg: 6
y
arg: 7
n
7 | $
(7 был код возврата).
Он не рекурсивно и не указывает циклы - вместо этого он просто называет себя, заменяя собственное пространство памяти новой версией самого себя.
Таким образом, стек никогда не будет переполняться, хотя все предыдущие переменные будут обновлены, как и при любой переустановке - вызов getchar
предотвращает 100% использование ЦП.
В случае самообновляющегося двоичного файла, поскольку весь бинарный файл (по крайней мере, в Unix-подобных, я не знаю о Windows) будет скопирован в память во время выполнения, а затем, если файл изменится на диск перед вызовом execve(argv[0], ...
новый бинарный файл, найденный на диске, не такой же старый, будет запущен вместо этого.
Как @CarstenS и @bishop указывают в комментариях, в связи с уникальным способом, в котором Unix была разработана, открытые файловые дескрипторы хранятся по fork
/exec
, и в результате для того, чтобы избежать утечки дескрипторов открытых файлов через звоните по номеру execve
, вы должны либо закрыть их до execve
, либо открыть их с помощью e
, FD_CLOEXEC
/O_CLOEXEC
в первую очередь - более подробную информацию можно найти на странице Dan Walsh's blog.
Независимо от того, что вы делаете, не вызывайте 'main()' в свой код. – NathanOliver
"перезапуск всех переменных вручную" Wut? – Treycos
Считаете ли вы использование цикла? –