Зачем нам нужен argc, если в конце argv всегда есть ноль?

117

Кажется, что argv[argc]всегда NULL, поэтому я думаю, что мы можем пройти по списку аргументов без argc. Один whileцикл сделает это.

Если NULLв конце всегда стоит a argv, зачем нам это argc?

StarPinkER
источник
17
Наверное, дело в удобстве. Предоставляет программисту простой способ выручить раньше, если не хватает аргументов, без зацикливания. В противном случае у нас наверняка были бы функции, int argc(char *argv[])
вызывающие
5
Для ясности "\0"- это не то же самое, что указатель NULL ( 0эквивалент NULL в C ++)
Матс Петерссон
31
Зачем нам нужно, чтобы argv [argc] был NULL, если у нас есть argc?
Ambroz Bizjak
7
Как еще вы могли бы определить количество аргументов за постоянное время?
avakar
4
Не думайте, что теги linux / unix здесь подходят, так как это поведение должно быть справедливо для всех компиляторов во всех операционных системах.
Даррел Хоффман

Ответы:

106

Да, argv[argc]==NULLгарантировано. См. C11 5.1.2.2.1 Запуск программы (выделено мной)

Если они объявлены, параметры основной функции должны подчиняться следующим ограничениям:

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

argcПоэтому обеспечение не жизненно важно, но все же полезно. Помимо прочего, он позволяет быстро проверить, что было передано правильное количество аргументов.

Изменить: вопрос был изменен, чтобы включить C ++. n3337 draft 3.6.1 Основная функция говорит

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

simonc
источник
36
И argcможет быть довольно большой, потому что оболочка делает расширение (так в расширяется за счет оболочки , прежде чем в исполняемый файл). В моей системе у меня может быть несколько сотен тысяч. ls **execve/bin/lsargc
Василий Старынкевич
Это довольно круто, это никогда не приходило мне в голову, поскольку я всегда считал argcдостаточным, но я определенно могу думать о ситуациях, когда эта гарантия была бы актуальной и даже необходимой. +1
Томас
6
@BasileStarynkevitch Время простого прохождения через массив значений указателей еще раз до NULL для получения счетчика является ничтожным по сравнению с временем, уже потраченным на создание массива указателей, и даже более несущественным по сравнению с фактическим использованием каждого значения аргумента в программе. А если просто проверить, больше ли количество аргументов N, то перебирать весь массив не нужно. Тем не менее, я полностью согласен, что это argcбыло и остается хорошо.
hyde
43

Да, argv[argc]гарантированно будет нулевой указатель. argcиспользуется для удобства.

Цитируя официальное объяснение из C99 Rationale, обратите внимание на слова избыточной проверки :

Обоснование международного стандарта - Языки программирования - C §5.1.2.2.1 Запуск программы

Описание argcи argvаргументы в пользу mainпризнания обширной предшествующей практики. argv[argc]должен быть нулевым указателем, чтобы обеспечить избыточную проверку конца списка, также на основе общепринятой практики.

Ю Хао
источник
19

Это по историческим причинам и совместимости со старым кодом. Первоначально не было гарантии, что в качестве последнего элемента массива argv будет существовать нулевой указатель. Но argc существовал всегда .

zentrunix
источник
... Что в некотором роде обидно. Если бы это было так int main(char *argv[], int argc, ...), то некоторые программы могли бы просто опустить, argcпотому что они им не нужны. Противоположное (нужно, argcно не нужно argv), вероятно, никогда не пригодится в реальной программе.
hyde
@hyde: см. комментарий Базиля Старынкевича выше
zentrunix
6

Он нам «нужен», потому что этого требуют разные стандарты.

Мы можем полностью игнорировать значение, но, поскольку это первый параметр main, мы должны иметь его в списке параметров. В C ++ (и, вероятно, в нестандартных диалектах C) вы можете просто опустить имя параметра, как этот фрагмент C ++ (легко преобразовать в C):

#include <stdio.h> // C-compatible include, guarantees puts in global namespace

// program will print contents of argv, one item per line, starting from argv[0]

int main(int /*argc*/, char *argv[]) { // uncomment argc for C

    //(void)argc; // uncomment statement for C

    for (int i=0; argv[i]; ++i) {
        puts(argv[i]);
    }

    return 0;
}

В стандартном C с настройками общих предупреждений неиспользуемый параметр генерирует предупреждение, которое можно исправить с помощью оператора, например, (void)argc;который заставляет использовать имя без генерации кода.

argcприятно иметь, потому что в противном случае многим программам пришлось бы проходить через параметры, чтобы получить счет. Кроме того, во многих языках программирования с массивами, имеющими длину, нет никаких argcпараметров, есть только массив с элементами.

Хайд
источник
Речь идет как о C, так и о C ++. В C имя параметра является обязательным.