Является ли "argv[0] = name-of-executable" принятым стандартом или просто общим соглашением?
при передаче аргумента main()
в приложении C или C++ будет argv[0]
всегда быть именем исполняемого файла? Или это просто общее соглашение и не гарантируется, чтобы быть истинным 100% времени?
7 ответов
догадки (даже образованные догадки) - это весело, но вам действительно нужно перейти к документам стандартов, чтобы быть уверенным. Например, ISO C11 заявляет (мой акцент):
, если значение
argc
больше нуля, то строка, на которую указываетargv[0]
представляет название программы;argv[0][0]
должен быть нулевым символом, если имя программы недоступно из среды хоста.
так что нет, это только имя программы если это имя доступен. и "является" название программы, не обязательно is название программы. В предыдущем разделе говорится:
, если значение
argc
больше нуля, члены массиваargv[0]
черезargv[argc-1]
inclusive должен содержать указатели на строки, которым задаются значения, определенные реализацией средой хоста до запуска программы.
это не изменилось с C99, предыдущий стандарт, и означает, что даже значения не продиктованы стандартом - это полностью зависит от реализации.
это означает, что имя программы может быть пустым, если среда хоста не предоставьте его, и что-нибудь еще, если среда хоста тут предоставьте его, при условии, что "что-нибудь еще" каким-то образом представляет имя программы. В мои более садистские моменты я бы рассмотрел перевод на суахили, запуск его через шифр подстановки, а затем сохранение его в обратном порядке байтов: -).
однако реализация определена тут имеют конкретное значение в стандартах ISO-реализация должна документировать, как она работает. Так что даже UNIX, который может поместить все, что ему нравится в argv[0]
С exec
семейство вызовов, должно (и делает) документировать его.
под *nix
системы типа exec*()
звонки argv[0]
будет все, что вызывающий абонент помещает в argv0
место в exec*()
звонок.
оболочка использует соглашение о том, что это имя программы, и большинство других программ следуют тому же соглашению, поэтому argv[0]
обычно имя программы.
но изгоев Unix программа может вызвать exec()
и сделать argv[0]
все, что ему нравится, поэтому независимо от того, что говорит стандарт C, вы не можете рассчитывать на это 100% время.
согласно стандарту C++, раздел 3.6.1:
argv[0] должен быть указателем на начальный характер NTMBS, который представляет имя, используемое для вызова программа или""
Так что нет, это не гарантируется, по крайней мере, стандартом.
на этой странице гласит:
элемент argv [0] обычно содержит имя программы, но на это не следует полагаться - в любом случае это необычно для программы, чтобы не знать свое собственное имя!
однако другие страницы, похоже, поддерживают тот факт, что это всегда имя исполняемого файла. этот гласит:
Вы заметите, что argv[0] - это путь и имя самой программы. Это позволяет программа для поиска информации о себе. Он также добавляет еще один к массиву аргументов программы, поэтому распространенной ошибкой при извлечении аргументов командной строки является захват argv[0], когда вы хотите argv[1].
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] = '';
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) */
а затем вам просто нужно разобрать строку, чтобы извлечь исполняемое имя из пути.
Я не уверен, является ли это почти универсальное соглашение или стандарт, но в любом случае вы должны соблюдать. Однако я никогда не видел, чтобы его использовали за пределами Unix и Unix-подобных систем. В средах Unix - и, возможно, особенно в старые времена-программы могут иметь значительно различное поведение в зависимости от имени, под которым они вызываются.
отредактировано: я вижу из других сообщений в то же время, что и мой, что кто-то определил его как исходящий из конкретного стандарт, но я уверен, что Конвенция давно предшествует стандарту.
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.