Вопрос

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

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

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

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

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

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

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

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

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

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

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

Решение

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

Другие советы

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

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]. */

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

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

if (argc > -1)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top