Является ли "argv[0] = имя исполняемого файла" принятым стандартом или просто общим соглашением?


при передаче аргумента main() в приложении C или C++, будет argv[0] всегда быть именем исполняемого файла? Или это просто общее соглашение и не гарантируется, что оно будет истинным в 100% случаев?

7 82

7 ответов:

догадки (даже образованные догадки) - это весело, но вам действительно нужно перейти к документам стандартов, чтобы быть уверенным. Например, ISO C11 гласит (мой акцент):

, если значение argc больше нуля, то строка, на которую указывает argv[0]представляет название программы; argv[0][0] должен быть нулевым символом, если имя программы недоступно из среды хоста.

так что нет, это только название программы если это имя доступен. и "является" имя программы, не обязательно и название программы. В предыдущем разделе говорится:

, если значение 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] должен быть указателем на начальный характер НТМБ, что представляет имя, используемое для вызова программа или ""

Так что нет, это не гарантируется, по крайней мере, по стандарту.

на этой странице гласит:

элемент 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.