Индекс массива и подпись argc - PullRequest
6 голосов
/ 14 марта 2010

Стандарт C ( 5.1.2.2.1 Запуск программы ) гласит:

Функция, вызываемая при запуске программы называется главным. [...]
Он должен быть определен с тип возврата int и без Параметры:
int main(void) { /* ... */ }

или с двумя параметрами [...] :
int main(int argc, char *argv[]) { /* ... */ }

А потом говорит:

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

  • Почему не следует argc определять как unsigned int, argc, предположительно означающее «количество аргументов»?
  • Следует ли использовать argc в качестве индекса для argv?

Так что я начал задаваться вопросом, говорит ли стандарт C что-то о типе индекса массива. Это подписано?

6.5.2.1 Подписка на массив :

Одно из выражений должно иметь тип 10 ‘ указатель на тип объекта ’ ’, другой выражение должно иметь целочисленный тип , и результат имеет тип ‘‘ type ’’.

Он ничего не говорит о своей подписи (или я ее не нашел). Довольно часто можно увидеть коды, использующие индексы массива негативов (array[-1]), но разве это не неопределенное поведение?

  • Должны ли индексы массива быть без знака?

Ответы [ 4 ]

6 голосов
/ 14 марта 2010

Причина int в main () историческая - так было всегда, задолго до того, как язык был стандартизирован. Требование индекса массива состоит в том, что он находится в пределах массива (или, в некоторых случаях, после конца) - все остальное не определено, поэтому подпись не имеет значения.

3 голосов
/ 15 марта 2010

Как правило, в C «принцип наименьшего удивления» подразумевает, что предпочтительно делать переменную со знаком, если для этого нет веской причины для неподписания. Это связано с тем, что правила продвижения типов могут приводить к неожиданным результатам при смешивании значений со знаком и без знака: например, если argc было без знака, то это простое сравнение приведет к неожиданным результатам:

if (argc > -1)

(-1 повышен до unsigned int, поэтому его значение преобразуется в UINT_MAX, что почти наверняка больше, чем argc).

3 голосов
/ 14 марта 2010

1) О типе main () argc: ИМХО стандарт продолжает очень давнюю традицию (более 30 лет!), И сейчас ... просто слишком поздно что-то менять (ПРИМЕЧАНИЕ: в большинстве систем нет компилятора, ни компоновщик, ни процессор не будут жаловаться, если "argc" определено как "unsigned", но вы не в стандарте!)

2) В большинстве реализаций argv [argc] допустим и имеет значение NULL. Действительно, альтернативный способ найти конец списка аргументов состоит в том, чтобы перебрать argv с 0, заканчивающегося, когда argv [i] равен NULL.

3) Арифметика массива / указателя с отрицательными числами допустима, поскольку диапазон адресов от (p-n) до p принадлежит одному и тому же объекту памяти. И.Е. вы можете иметь

char array[100];
char *p;

p = &array[50];
p += -30; /* Now p points to array[20]. */

Такое использование арифметики с указателями допустимо, поскольку результирующий указатель все еще остается внутри исходного объекта памяти («массива»). В большинстве систем арифметика указателей может использоваться для навигации в памяти с нарушением этого правила, но это НЕ переносимо, поскольку полностью зависит от системы.

0 голосов
/ 14 марта 2010

1) Argc - это число аргументов, но, если честно, как вы можете добавить аргумент перед именем программы, которое argv[0]. Представьте себе программу под названием foo, вы не можете просто сказать args1 foo args2, поскольку это бессмысленно, несмотря на то, что argc является типом со знаком int, то есть не существует такой вещи, как argv[-1], которая получит вам 'args1'. ..

2) Причина, по которой argc на самом деле не является индексом вектора аргумента (следовательно, ' argv '), поскольку во время выполнения имя исполняемой программы вставляется в нулевое смещение, т. Е. argv[0] следовательно, argc будет выключен на 1.

3) Индексы массива, с точки зрения манипулирования указателем, при условии вы находитесь в границах блока памяти, в котором находится указатель, использование индексов массива как отрицательных допустимо поскольку индексы массива являются ярлыками для указателей, и не только они являются коммутативными, например

char v[100];
char *p = &v[0];

You can do this:

p[55] = 'a'; 

Which is the same as

*(p + 55) = 'a';

You can even do this:

p = &v[55];

p[-10] = 'b' /* This will stuff 'b' into 45'th offset! */

Which is the same as

*(p - 10) = 'b';

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

4) В * nix-средах некоторым будет предоставлен третий параметр, предоставленный main char **endvp, опять же, он редко используется в мире Microsoft для DOS / Windows. В некоторых реализациях * nix времени выполнения, по предысторическим причинам, вы могли передавать переменные среды через среду выполнения.

...