Может ли argv [0] содержать пустую строку?

В любой программе на C аргумент командной строки argv[0] указывает на имя, используемое для вызова программы. Есть ли какие-либо обстоятельства, при которых он будет указывать на пустую строку ""?

Пример фрагмента кода для такого случая будет хорошей ссылкой.


person Sangeeth Saravanaraj    schedule 29.12.2011    source источник
comment
Почему бы не разработать свою программу так, чтобы она работала независимо? Или используйте утверждение времени выполнения.   -  person tangrs    schedule 29.12.2011
comment
Лучше называть это пустой строкой; пустую строку слишком легко спутать с нулевым указателем.   -  person Jonathan Leffler    schedule 29.12.2011
comment
@JonathanLeffler: отредактировано   -  person Keith Thompson    schedule 29.12.2011
comment
связанные: NULL: stackoverflow.com/questions / 2794150 / when-can-argv0-have-null /   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 17.02.2017


Ответы (4)


Его реализация определена. §5.1.2.2.1 сокращенный:

  • Если значение argc больше нуля, элементы массива с argv[0] по argv[argc-1] включительно должны содержать указатели на строки, которым перед запуском программы передаются значения, определяемые реализацией. Цель состоит в том, чтобы предоставить программе информацию, определенную до ее запуска, из другого места в размещенной среде. [...]

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

Итак, если argc больше нуля, вполне намерением, что argv[0] никогда не будет пустой строкой, но это может случиться. (Обратите внимание, что с argc равным n, argv[0] по argv[n - 1] никогда не равны нулю и всегда указывают на строку. Однако сама строка может быть пустой. Если n равно нулю, argv[0] равно нулю.)

На практике, конечно, вам просто нужно убедиться, что платформы, на которые вы нацелены, ведут себя должным образом.

person GManNickG    schedule 29.12.2011
comment
Фактически, если argv[0][0] может быть 0, argv[0] может быть пустым. - person alk; 29.12.2011
comment
@alk: argv[0] никогда не имеет значения NULL, если argc больше нуля, но может указывать на пустую строку. - person GManNickG; 29.12.2011
comment
@KeithThompson: Вы называете это ... ;-) - person alk; 29.12.2011
comment
@GMan Спасибо за ответ. Не могли бы вы сообщить мне, откуда вы взяли спецификацию C? например Откуда вы берете информацию о 5.1.2.2.1? - person Sangeeth Saravanaraj; 29.12.2011
comment
@SangeethSaravanaraj: Это последний проект. стандарта C99. Это последний доступный проект недавно опубликованного стандарта 2011 года. - person Keith Thompson; 29.12.2011

да.

Стандарт языка C явно допускает возможность того, что argv[0] может быть нулевым указателем, или, что он может указывать на пустую строку (""). N1256 5.1.2.2.1p2:

Значение argc должно быть неотрицательным.

argv [argc] должен быть нулевым указателем.

[...]

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

В Unix-подобных системах программы вызываются одной из exec() семейства функций (execl(), execlp() и т. Д.), Что позволяет вызывающей стороне точно указать, какие аргументы передаются функции main(). (Можно даже вызвать программу способами, которые нарушают требования, налагаемые стандартом C.)

Обратите внимание, что в стандарте сказано, что argv[0] (при условии, что он не пустой и не пустой) «представляет имя программы». Стандарт намеренно расплывчато описывает, как он представляет имя программы. В частности, ему не нужно указывать имя, по которому программа может быть вызвана (поскольку стандарт даже не требует, чтобы программы могли быть вызваны по имени).

person Keith Thompson    schedule 29.12.2011
comment
Оно не может быть пустым, просто пустым. В предыдущем абзаце требуется, чтобы каждый argv указывал на строку (и чтобы последний был нулевым). Дрянная реализация могла бы предоставить им все пустые строки, но не все пустые. - person GManNickG; 29.12.2011
comment
Если argc == 0, то argv[0] является нулевым указателем. (Я не цитировал эту часть, когда вы писали свой комментарий.) - person Keith Thompson; 29.12.2011
comment
Это было не так. Однако я проголосовал "за", так как наши ответы похожи. - person GManNickG; 29.12.2011
comment
@KeithThompson +1 за упоминание семейства функций exec()! Спасибо!! - person Sangeeth Saravanaraj; 29.12.2011

В других ответах цитируется стандарт C и показано, что argv[0] и может быть NULL или это может быть пустая строка (""). Вы должны писать свою программу с предположением, что это может произойти, потому что в противном случае вы создаете (небольшой) риск безопасности. Вызвать вашу программу и установить argv на все, что захочет злоумышленник, легко. В качестве доказательства рассмотрим следующие две программы. Первый, echoargv.c, распечатывает содержимое argv:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
    int i;
    for (i = 0; i < argc; ++i)
        printf("argv[%d] = \"%s\"\n", i, argv[i]);
    exit(0);
}

Второй, argv0, вызывает любую другую программу и позволяет пользователю указать argv другой программы:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv) {
    (void) execv(argv[1], argv+2);
    perror("execv");
    exit(1);
}

(Это версия для Posix. Нестандартные среды могут потребовать изменений.)

Вот как их использовать:

$ gcc -o echoargv echoargv.c 
$ gcc -o argv0 argv0.c 
$ ./argv0 ./echoargv 
$ ./argv0 ./echoargv ''
argv[0] = ""
$ ./argv0 ./echoargv 'this is fun' 'it is fun indeed'
argv[0] = "this is fun"
argv[1] = "it is fun indeed"
$ 

Первый запуск argv0 устанавливает argv[0] echoargv равным NULL. Второй прогон делает это пустой строкой. Третий запуск делается просто для развлечения: обратите внимание, что argv[0] не обязательно иметь какое-либо отношение к фактическому имени программы.

Как это может тебя укусить? Если, например, вы вслепую распечатываете имя своей программы в сообщении об использовании:

printf("usage: %s [options] [FILE]...\n", argv[0]);

Лучше:

const char *program_name = "some default name"; /* (global) variable */
if (argv[0] && argv[0][0])
    program_name = argv[0];
printf("usage: %s [options] [FILE]...\n", program_name);

Если вы этого не сделаете, злоумышленник может вызвать отказ вашей программы по своему желанию или может заставить вашу программу сообщать пользователю о совершенно неправильных вещах.

person Community    schedule 29.12.2011
comment
+1 за классный пример! Было действительно очень весело читать ваш пост !! Спасибо :) - person Sangeeth Saravanaraj; 29.12.2011

argv [0] может иметь значение NULL в C, например, если вы напрямую вызываете основную функцию (некоторые трюки могут быть выполнены в C). Я не знаю, допускает ли C ++ прямой основной вызов.

person BigMike    schedule 29.12.2011
comment
Разве OP не спрашивает о argv[0], относящемся к пустой строке ("", {'\0'}), а о том, что argv[0] является NULL? - person alk; 29.12.2011
comment
@alk OP - это пустая / нулевая строка, а не argv[0]=NULL - person Sangeeth Saravanaraj; 29.12.2011
comment
C ++ не позволяет вызывать main(); C делает. - person Jonathan Leffler; 29.12.2011
comment
если может быть нулевым, то тоже может быть пустым (\ 0). Суть ответа - когда main не вызывается системой. Пример ? ну, вы можете написать main на C, который рекурсивно вызывает себя, не передавая argv. в C main - это просто функция. Однако я считаю, что вызывать main напрямую - это плохая чертовски плохая практика. Но мы ведь не говорим о хороших или плохих практиках? Подробнее об этом читайте в ответах GMan & Keith. Они лучше моих (даются и рефери). - person BigMike; 29.12.2011
comment
@BigMike +1 за упоминание прямого вызова main(). Спасибо! - person Sangeeth Saravanaraj; 29.12.2011
comment
@JonathanLeffler: только что протестирован с компилятором MS, C ++ не позволяет этого. ИМХО - хороший выбор дизайна. за более чем 10 лет программирования на C я видел прямой главный вызов только один раз, и мне все еще интересно, почему ... но он был в коде столь определенного гения, поэтому у меня не было возможности спросить или спорить. - person BigMike; 29.12.2011