Безопасно ли переименовывать argc и argv в основной функции?

82

Многие программы используют стандартные имена для ряда аргументов и массивов строк. Прототип основных функций выглядит следующим образом : int main(int argc, char *argv[]);. Но сломаю ли я что-нибудь, если выберу для этих переменных собственные имена?

Например int main(int n_of_args, char *args[]);

В контексте компилятора все нормально. Эти переменные являются локальными для основной функции, поэтому могут иметь любые имена. И простой код создается и работает отлично. Но эти имена могут использоваться препроцессором. Так безопасно ли переименовывать эти аргументы?

PS Лично мне эти имена кажутся плохими, потому что они очень похожи и отличаются только одной буквой. Но КАЖДЫЙ использует их по какой-то причине.

Янпа
источник
21
Да, совершенно безопасно.
Дэвид Хельзер
55
Как говорят все ответы, да, это безопасно. Но, пожалуйста, не делай этого. Все знают, что argcи argvесть. n_of_argsи argsможет быть понятнее для тех, кто не знает C или C ++, но это не ваша аудитория.
Кейт Томпсон
4
Вы можете это сделать, это еще не повод для этого. Все знают, что это такое, и ожидают, что они будут такими.
SergeyA
10
Если вопрос точно «сломаю ли я что-нибудь, если выберу нестандартные имена», то точный ответ будет «да, вы нарушите устоявшуюся традицию»;)
Frax
12
Просто переверните их! .. и с самого начала вы закладываете фундамент для гарантии занятости :)
yano

Ответы:

121

Да, это безопасно, если вы используете допустимые имена переменных. Это локальные переменные, поэтому их область действия не выходит за рамкиmain функции.

Из раздела 5.1.2.2.1 стандарта C :

Называется функция, вызываемая при запуске программы main. Реализация не объявляет прототипа для этой функции. Он должен быть определен с возвращаемым типом intи без параметров:

int main(void) { /*  ... */ }

или с двумя параметрами (называемыми здесь argcи argv, хотя могут использоваться любые имена, поскольку они являются локальными для функции, в которой они объявлены ):

int main(int argc, char *argv[]) { /* ...   */ }

или эквивалент; или каким-либо другим способом, определяемым реализацией

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

dbush
источник
38

Имена argcи argvбыли фактически предписаны стандартом C ++ до C ++ 11. В нем говорилось:

Все реализации должны допускать оба следующих определения main:

int main ()

и

int main ( int argc , char * argv [])

и пошел , чтобы обсудить требования argcиargv .

Таким образом, технически любая программа с другими именами не соответствовала стандарту, и компилятору было разрешено ее отклонить. На самом деле, конечно, ни один компилятор не сделал этого. См. Эту ветку на comp.std.c ++ или раздел 3.6.1 этого проекта стандарта C ++ 03. .

Это почти наверняка был простой недосмотр и был изменен в C ++ 11, который вместо этого говорит

Все реализации должны допускать как

  • функция возврата () int и
  • функция ( int, указатель на указатель char), возвращающаяint

как тип main(8.3.5). В последней форме, с целью демонстрации, вызывается первый параметр функции, argcа второй параметр функции argv,…

Ник Маттео
источник
29

Конечно , вы можете переименовать эти параметры безопасно , как вам нравится

 int main(int wrzlbrnft, char* _42[]) {
 }

Имена написаны песком. Они не влияют на окончательно скомпилированный код.


Единственное, что имеет значение, это то, что типы объявления и определения действительно совпадают.

Подпись main()функции внутренне объявлена ​​как

 int main(int, char*[]);

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

πάντα ῥεῖ
источник
5
только некоторые идентификаторы «написаны на песке», как вы выразились. имена функций, конечно же, нет.
Стив Кокс,
1
@SteveCox "имена функций, конечно, нет". В конце концов, они есть. Просто количество песчинок :-P ...
πάντα ῥεῖ
3
хорошо, но серьезно. после компиляции в объектном коде все еще есть имена функций. в противном случае связывание не сработало бы
Стив Кокс
4
@ πάνταῥεῖ: Если вы не приложите особых усилий для их удаления, имена функций останутся в конечном исполняемом файле.
Ник Маттео,
1
@Kundor: После связывания в Windows все не специальные функции не сохраняют имена
Дэни
15

Да. Это безопасно, выглядит странно, но ничего не сломает.

coredump
источник
7

Да, использовать разные имена безопасно.

Лично я бы не рекомендовал его, поскольку традиционный argcиargv так широко известен и знакомы с любым другим C программиста , который мог бы когда - либо работать с вашим кодом. В конечном итоге использование ваших собственных, особых, разных имен вызовет у ваших читателей гораздо больше путаницы и / или разочарования, чем когда-либо спасет вас, потому что вам больше нравятся ваши имена.

«Находясь в Риме, делайте, как римляне».

Стив Саммит
источник
Тем не менее, существует несколько вполне очевидных сценариев, требующих использования разных имен, один из самых известных - инициализация GLUT, glutInit(&argc, argv)где аргументы должны быть объявлены и инициализированы по-разному, чтобы не позволить GLUT съесть аргументы командной строки, если мы этого не хотим. SO link
user3078414
@ user3078414 Интересный пример, но я не понимаю, как он говорит о том, какие имена должны быть названы. Согласно примерам в этом другом вопросе, мы могли бы легко написать int dummyargc = 1; char *dummyargv[1] = {(char*)"Something"}; glutInit(&dummyargc, dummyargv);.
Стив Саммит
Спасибо, @ steve-summit. Некоторая документация по API может вводить в заблуждение, поэтому этот поток наиболее полезен для выделения argc argvсоглашения об именах, как и ваш ответ. Я просто поставил свой комментарий в качестве примера предпочтительного использования любых других имен. Вот ссылка SO
user3078414
5

Да, вы можете переименовать их, как хотите. Это просто имена параметров функций, не более того.

орбита ковбой
источник
3

Я чувствую, что все хорошо и хорошо изучили технические правила C ++: ответ - да. Давайте отбросим традицию и тот факт, что эта 1 конкретная функция является особенной и знаковой, которая содержит действительные моменты, которые нельзя изменять на этой основе.

Часто мне кажется, что философия выбора редко обсуждается, и поэтому я хотел бы предложить точку зрения на этот вопрос, поскольку я считаю, что это важно для причины, по которой это было задано для начала.

Этот вопрос для меня связан с выбором выражения английского языка в коде в целом. Кажется, вас беспокоят краткие описания, в частности, если короткая рука содержит похожий текст. Однако в вашем примере изменение argn на n_of_args выполняет изменение только одного типа сокращенной записи в другую форму сокращения без добавления реального значения: пояснения или других видимых свойств.

Слово «число» заменено буквой «н».

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

main (int аргументCount, char ** аргументVector)

Я всегда думаю о двух вещах: называть вещи тем, чем они являются, и / или их подразумеваемым использованием. Называть его аргументомVector для меня излишне, поскольку свойство быть вектором подразумевается двойным косвенным обращением **. Таким образом, лучший вариант написания кода: ** аргументы.

Некоторые скажут, что переменная с именем argumentsCount объявлена ​​как int, а Count не может быть отрицательным, но вы можете иметь отрицательное int {unsigned is better}.

Опять же, что это и как используется, играет важную роль в этой интерпретации. Если это счетчик, то я предполагаю, что он никогда не будет отрицательным. В конце концов, как можно получить графу -2 яблока. Я бы сказал, ты ВЛАДЕЛА двумя яблоками. Если это число, то я ожидаю, что возможен отрицательный случай. Вот почему дополнительное слово «of», вероятно, важно для вас. Это и, возможно, число, на которое ссылается коллекция, подразумевает конкретный элемент, а не свойство самой коллекции. То есть: argumentsNumber = 5 подразумевает конкретный аргумент, но не numberOfArguments.

main (int maxArgumentsIndex, char ** аргументы).

Это устраняет двусмысленность. Назвав его индексом, вы удалите отрицательную двусмысленность в регистре, а также опишете, что это такое, и, кроме того, как его использовать. Английская формулировка также подразумевает, что max является абсолютным и может показаться странным при написании кода, изменяющего это значение (оно должно быть const). Слово «аргументы» имеет здесь смысл, поскольку оно существует во множественном числе, описывает, что это такое и как его уже следует использовать. Даже интерпретация этого способа может быть опасной, поскольку индекс равен -1 от Count / NumberOf. 5 аргументов дают maxIndex 4 !!

Любая другая функция, и я бы полностью использовал:

функция void (const unsigned int maxArgumentsIndex, const char ** аргументы)

Не все ситуации заслуживают подробных описаний. На самом деле, иногда короткая стрелка дает больше читабельности, в частности, в случае написания математических классов, таких как Vec3f, Matrix, Quaternion и т. Д. Я почти всегда буду пытаться сопоставить математический язык, а не лингвистический. . float x, y, z vrs. float xComponent и тому подобное.

Я понимаю, что все это - выбор стиля, но осознание выбора действительно поможет в долгосрочной перспективе. Я гарантирую, что опытные программисты будут беспокоиться, когда массивы не записываются во множественном числе, но опять же, main - это особая проза существования;)

JMan Mousey
источник
2

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

argc --> argument count

argv --> argument vector

что также имеет смысл с точки зрения использования, поэтому вы можете изменить имя на любое, кроме Reserved names

В GCC выполнение программы начинается с имени функции main оно не зависит от ее параметров.

Когда вы пишете автономную программу для микроконтроллеров, вам не нужно беспокоиться об имени, mainвместо этого вы можете определить свое собственное nameи изменить Assembly entry_point, чтобы указать вашу функцию. Это зависит от компилятора контроллера и наличия предопределенного исходного кода контроллера. Я сделал это в контроллере Freescale под Code-warrior.

Моя заметка:

Лучше следовать общим стандартам / стилю кода, чтобы код был более заметным и читаемым.

ntshetty
источник
0

Для компилятора это безопасно.

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

int main(int foo, char ** bar)
{
    int argc;
    float argv;

Но я не думаю, что мне нужно говорить, насколько это будет плохой практикой.

Klutt
источник
-1

Если вам не нравятся имена переменных, почему бы не заменить их макросом #define :

#define yourCounterName argc
#define yourVectorName  argv 

Вы не будете рисковать и получите «чистое решение».

Фифи
источник
Это не константы, это просто подстановка.
Дэвид Данэм