Чи безпечно перейменовувати 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
Ви можете це зробити, для цього недостатньо підстав. Усі знають, що це таке, і вони справді очікують, що вони будуть такими.
Сергій

10
Якщо питання саме "чи я б щось зламав, якщо вибрав власні імена", то точна відповідь "так, ти порушив би усталену традицію";)
Фракс,

12
Просто переверніть їх! .. і з самого початку ти закладаєш фундамент безпеки роботи :)
yano

Відповіді:


121

Так, це безпечно, якщо ви використовуєте дійсні імена змінних. Вони є локальними змінними, тому область їх дії не виходить за межі mainфункції.

З розділу 5.1.2.2.1 стандарту С :

Функція, що викликається під час запуску програми, називається main. Реалізація не оголошує прототипу для цієї функції. Він повинен визначатися з типом повернення intта без параметрів:

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

або з двома параметрами (тут іменуються argcі argv, хоча можуть бути використані будь-які імена, оскільки вони є локальними для функції, в якій вони оголошені ):

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

або еквівалент; або якимось іншим способом, визначеним реалізацією

З огляду на це , використання будь-чого іншого, крім argcі argvможе заплутати інших, хто читає ваш код, які звикли до загальноприйнятих назв цих параметрів. Так що краще помилитися на стороні ясності.


38

Назви argcта argvфактично були передбачені стандартом C ++ до C ++ 11. У ній зазначалося:

Усі реалізації повинні дозволяти обидва наступних визначення основного:

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 усі неспеціальні функції не зберігають імен
Дані,


7

Так, безпечно використовувати різні імена.

Особисто я б не рекомендував його, як традиційний argcі argvтакий широко відомий і знайомий кожному іншому програмісту на С, який коли-небудь міг працювати з вашим кодом. Зрештою, використання власних, особливих, різних імен спричинить у читачів набагато більше розгубленості та / або розчарування, ніж коли-небудь врятує вас, бо ваші імена вам більше подобаються.

"Коли ти в Римі, роби так, як роблять римляни".


Тим не менше, є кілька цілком очевидних сценаріїв, що вимагають використання різних імен, горезвісний - це ініціалізація GLUT, glutInit(&argc, argv)де аргументи повинні оголошуватися та ініціалізуватися по-різному, щоб не дати GLUT з'їдати аргументи командного рядка, якщо ми цього не хочемо. SO посилання
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 виконує лише зміну одного типу короткої руки на іншу форму скорочення без реального додавання вартості: уточнення чи інших видимих ​​властивостей.

Слово "номер" замінено літерою "n".

Якщо ви змінюєте ім'я короткої руки за допомогою філософії антикороткої руки, то щось подібне може здатися більш доречним:

main (int argumentCount, char ** argumentVector)

Я завжди думаю про дві речі: називати речі тим, що вони є, та / або їх прихованим використанням. Називати це argumentVector для мене зайвим, оскільки властивість бути вектором передбачається подвійною опосередкованістю **. Таким чином, краща довга рука для того, як я писав би код: ** аргументи.

Дехто сказав би, що змінна з іменем argumentCount оголошена як int, і Count не може бути від'ємним, але ви можете мати від'ємний int {unsigned is better}.

Знову ж таки, що це і як воно використовується, відіграє важливу роль у цій інтерпретації. Якщо це граф, то я б припустив, що це ніколи не буде негативним. Врешті-решт, як ви можете мати кількість -2 яблука. Я б сказав, ви в боргу два яблука. Якщо це число, то я би очікував, що можливий негативний випадок. Ось чому додаткове слово "з", ймовірно, важливо для вас. Це, і, можливо, число, яке називається колекцією, означає певний предмет, а не властивість самої колекції. Тобто: argumentNumber = 5 передбачає конкретний аргумент, але не numberOfArguments.

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

Це усуває двозначність. Називання його індексом усуває негативну двозначність, а також описує, що це таке, і додатково, як ним користуватися. З англійських формулювань це також передбачає, що max - це абсолют, і це буде дивно писати код, який змінює це значення (воно повинно бути const). Тут аргумент має сенс, оскільки він є множинним, описує, що це таке, і як його вже слід використовувати. Навіть таке тлумачення може бути небезпечним, оскільки індекс становить -1 від Count / NumberOf. 5 аргументів дають максимум 4!

Будь-яка інша функція, і я б повністю використав:

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

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

Я розумію, що все це вибір стилю, але усвідомлення вибору дійсно допоможе в довгостроковій перспективі. Я гарантую, що досвідчених програмістів турбує, коли масиви не пишуться у множині, але знову ж таки, головне - це спеціальна проза існування;)


2

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

argc --> argument count

argv --> argument vector

що також має сенс з точки зору використання, тому ви можете змінити будь-яку назву, яку очікуєте Reserved names

У GCC виконання програми починається з назви функції, mainяка не залежить від його параметрів.

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

Моя примітка:

Краще дотримуватися загальноприйнятих стандартів / стилю коду, щоб зробити код більш помітним і читабельним


0

Що стосується компілятора, це безпечно.

Єдина проблема, яку це може спричинити, - плутанина. Люди, які читають ваш код, очікуватимуть, що ці дві змінні матимуть свої стандартні імена. Можна навіть зробити щось подібне:

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

Але я не думаю, що мені потрібно говорити, наскільки це була б погана практика.


-1

Якщо вам не подобаються імена змінних, чому б не замінити їх макросом #define :

#define yourCounterName argc
#define yourVectorName  argv 

Ви не підете на ризик і не вийде «чисте рішення».


Це не константи, просто заміна.
Девід Данхем,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.