При передаче аргумента в main()
в приложении C или С++ будет argv[0]
всегда имя исполняемого файла? Или это просто обычное соглашение и не гарантируется в 100% случаев?
Является ли "argv [0] = имя исполняемого" принятым стандартом или просто общим соглашением?
Ответ 1
Догадки (даже образованные догадки) - это весело, но вам действительно нужно пойти в стандартную документацию, чтобы быть уверенным. Например, ISO C11 заявляет (мой акцент):
Если значение
argc
больше нуля, строка, на которую указываетargv[0]
, представляет имя программы;argv[0][0]
должен быть нулевым символом, если имя программы недоступно в среде хоста.
Нет, это просто имя программы, если это имя доступно. И он "представляет" имя программы, не обязательно является именем программы. В разделе до этого указывается:
Если значение
argc
больше нуля, элементы массиваargv[0]
черезargv[argc-1]
включительно должны содержать указатели на строки, которым перед запуском программы заданы значения, заданные реализацией.
Это не изменилось с C99, предыдущего стандарта, и означает, что даже значения не продиктованы стандартом - полностью до реализации.
Это означает, что имя программы может быть пустым, если среда хоста не предоставляет его, и что-либо еще, если среда-хост обеспечит ее, при условии, что "что-либо еще" каким-то образом представляет имя программы. В мои более садистские моменты я бы подумал о переводе его на суахили, пропустив его через шифр замещения, а затем сохранил его в обратном порядке байта: -).
Однако определенные в реализации значения имеют определенное значение в стандартах ISO - реализация должна документировать, как это работает. Таким образом, даже UNIX, который может поместить все, что ему нравится, в argv[0]
с семейством вызовов exec
, должен (и делает) документировать его.
Ответ 2
В системах *nix
с вызовами exec*()
argv[0]
будет тем, что вызывающий объект помещает в argv0
в вызове exec*()
.
В оболочке используется соглашение о том, что это имя программы, и большинство других программ соответствуют одному и тому же соглашению, поэтому argv[0]
обычно имя программы.
Но программа-мошенник Unix может вызывать exec()
и делать argv[0]
все, что ему нравится, поэтому независимо от того, что говорит стандарт C, вы не можете рассчитывать на это 100% времени.
Ответ 3
В соответствии со стандартом С++, раздел 3.6.1:
argv [0] должен быть указателем на начальный характер NTMBS, который представляет имя, используемое для вызова программы или ""
Нет, это не гарантирует, по крайней мере, Стандартом.
Ответ 4
Эта страница гласит:
Элемент argv [0] обычно содержит имя программы, но на это не следует полагаться - в любом случае необычно, что программа не знает свое имя!
Однако другие страницы, похоже, поддерживают тот факт, что он всегда является именем исполняемого файла. В этом говорится:
Вы увидите, что argv [0] - это путь и имя самой программы. Это позволяет программе обнаруживать информацию о себе. Он также добавляет еще один массив аргументов программы, поэтому общая ошибка при извлечении аргументов командной строки заключается в том, чтобы захватить argv [0], когда вы хотите argv [1].
Ответ 5
В ISO-IEC 9899 указано:
5.1.2.2.1 Запуск программы
Если значение
argc
больше нуля, строка, на которую указываетargv[0]
, представляет собой имя программы;argv[0][0]
должен быть нулевым символом, если имя программы недоступно в среде хоста. Если значениеargc
больше единицы, строки, на которые указываетargv[1]
, черезargv[argc-1]
, представляют параметры программы.
Я также использовал:
#if defined(_WIN32)
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
}
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */
#include <unistd.h>
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
pathName[pathNameSize] = '\0';
return pathNameSize;
}
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */
#include <mach-o/dyld.h>
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
uint32_t pathNameSize = 0;
_NSGetExecutablePath(NULL, &pathNameSize);
if (pathNameSize > pathNameCapacity)
pathNameSize = pathNameCapacity;
if (!_NSGetExecutablePath(pathName, &pathNameSize))
{
char real[PATH_MAX];
if (realpath(pathName, real) != NULL)
{
pathNameSize = strlen(real);
strncpy(pathName, real, pathNameSize);
}
return pathNameSize;
}
return 0;
}
#else /* else of: #elif defined(__APPLE__) */
#error provide your own implementation
#endif /* end of: #if defined(_WIN32) */
И тогда вам просто нужно проанализировать строку, чтобы извлечь исполняемое имя из пути.
Ответ 6
Я не уверен, что это почти универсальное соглашение или стандарт, но в любом случае вы должны соблюдать его. Однако я никогда не видел, чтобы он использовался вне Unix и Unix-подобных систем. В средах Unix - и, возможно, особенно в старые времена - программы могут иметь существенно различное поведение в зависимости от имени, под которым они вызывают.
EDITED: я вижу из других сообщений одновременно с моим, что кто-то определил его как исходящий из определенного стандарта, но я уверен, что соглашение давно предшествует стандарту.
Ответ 7
Runnable POSIX execve
пример, где argv[0] !=
исполняемое имя
Другие упомянули exec
, но вот пример выполнения.
a.c
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *argv[] = {"yada yada", NULL};
char *envp[] = {NULL};
execve("b.out", argv, envp);
}
b.c
#include <stdio.h>
int main(int argc, char **argv) {
puts(argv[0]);
}
Тогда:
gcc a.c -o a.out
gcc b.c -o b.out
./a.out
дает:
yada yada
Да, argv[0]
также может быть:
Протестировано на Ubuntu 16.10.