Индекс массива и argc со знаком

В стандарте C (5.1.2.2.1 запуска Программы) говорится:

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

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

И позже говорит:

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

  • Почему не был должен argc будьте определены как unsigned int, argc предположительно, означающее 'количество аргумента'?
  • Если argc используйтесь в качестве индекса для argv?

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

6.5.2.1 Индексирование массива:

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

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

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

6
задан Deduplicator 6 February 2018 в 18:08
поделиться

4 ответа

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

6
ответ дан 10 December 2019 в 00:36
поделиться

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 по доисторическим причинам можно было передавать переменные среды через среду выполнения.

-2
ответ дан 10 December 2019 в 00:36
поделиться

В общем случае в Си "принцип наименьшего удивления" подразумевает, что предпочтительнее делать переменную знаковой, если нет веских причин для того, чтобы она была беззнаковой. Это связано с тем, что правила приведения типов могут привести к неожиданным результатам, когда вы смешиваете знаковые и беззнаковые значения: например, если argc была беззнаковой, то это простое сравнение привело бы к неожиданным результатам:

if (argc > -1)

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

3
ответ дан 10 December 2019 в 00:36
поделиться

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

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

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

char array[100];
char *p;

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

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

3
ответ дан 10 December 2019 в 00:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: