Czy zmiana nazw argc i argv w funkcji main jest bezpieczna?


82

Wiele programów używa standardowych nazw dla wielu argumentów i tablic łańcuchów. Prototyp wygląda głównych funkcji takich jak: int main(int argc, char *argv[]);. Ale czy mógłbym coś zepsuć, wybierając niestandardowe nazwy dla tych zmiennych?

Na przykład int main(int n_of_args, char *args[]);

W kontekście kompilatora wszystko jest w porządku. Te zmienne są lokalne dla funkcji głównej, więc mogą mieć dowolne nazwy. Prosty kod buduje się i działa doskonale. Ale te nazwy mogą być używane przez preprocesor. Czy więc zmiana nazw tych argumentów jest bezpieczna?

PS Osobiście uważam te nazwy za złe, ponieważ wyglądają bardzo podobnie i różnią się tylko jedną literą. Ale KAŻDY używa ich z jakiegoś powodu.


21
Tak, całkowicie bezpieczne.
David Hoelzer

55
Jak mówią wszystkie odpowiedzi, tak, jest to bezpieczne. Ale proszę, nie rób tego. Każdy wie, czym argci argvsą. n_of_argsi argsmoże być bardziej zrozumiałe dla kogoś, kto nie zna C lub C ++ - ale to nie są Twoi odbiorcy.
Keith Thompson

4
Możesz to zrobić, to nie jest wystarczający powód, aby to zrobić. Wszyscy wiedzą, co to jest i spodziewają się, że takie będą.
SergeyA

10
Jeśli pytanie brzmi dokładnie „czy mógłbym coś zepsuć, jeśli wybrałbym nazwy niestandardowe”, to dokładna odpowiedź brzmi „tak, złamałbyś ugruntowaną tradycję”;)
Frax

12
Po prostu je odwróć! .. i od samego początku
kładziesz

Odpowiedzi:


121

Tak, jest to bezpieczne, o ile używasz prawidłowych nazw zmiennych. Są zmiennymi lokalnymi, więc ich zakres nie wykracza pozamain funkcję.

Z sekcji 5.1.2.2.1 normy C :

Nazwa funkcji wywoływana podczas uruchamiania programu main. Implementacja nie deklaruje żadnego prototypu dla tej funkcji. Powinien być zdefiniowany z typem zwracanym inti bez parametrów:

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

lub z dwoma parametrami (określanymi tutaj jako argci argv, chociaż można używać dowolnych nazw, ponieważ są one lokalne dla funkcji, w której zostały zadeklarowane ):

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

lub odpowiednik; lub w inny sposób określony w implementacji

Biorąc to pod uwagę, używanie czegokolwiek innego niż argci argvmoże zmylić innych czytających Twój kod, którzy są przyzwyczajeni do konwencjonalnych nazw tych parametrów. Więc lepiej błądzić po stronie jasności.


38

Nazwy argci argvbyły faktycznie wymagane przez standard C ++ przed C ++ 11. Stwierdził:

Wszystkie implementacje pozwalają na obie z następujących definicji main:

int main ()

i

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

i przeszedł do omówienia wymagań na temat argci argv.

Tak więc technicznie rzecz biorąc, każdy program używający innych nazw nie był zgodny ze standardami i kompilator mógł go odrzucić. Oczywiście żaden kompilator tego nie zrobił. Zobacz ten wątek w comp.std.c ++ lub sekcję 3.6.1 tego szkicu standardu C ++ 03 .

Było to prawie na pewno zwykłe przeoczenie i zostało zmienione w C ++ 11, który zamiast tego mówi

Wszystkie implementacje powinny umożliwiać jedno i drugie

  • funkcja () zwracająca inti
  • funkcja ( int, wskaźnik do wskaźnika char) zwracającaint

jako typ main(8.3.5). W tej ostatniej postaci, dla celów ekspozycji, wywoływany jest pierwszy parametr funkcji, argca drugi parametr funkcji argv,…


29

Oczywiście, możesz bezpiecznie zmieniać nazwy tych parametrów, jak chcesz

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

Imiona są zapisane piaskiem. Nie mają żadnego wpływu na ostatecznie skompilowany kod.


Liczy się tylko to, że typy parametrów deklaracji i definicji faktycznie pasują.

Podpis main()funkcji jest wewnętrznie deklarowany jako

 int main(int, char*[]);

jeśli chcesz ich użyć w implementacji, musisz je nazwać. To, które nazwy są używane, jest właściwie nieistotne, jak wspomniano wcześniej.


5
tylko niektóre identyfikatory są „zapisane w piasku”, jak to ująłeś. nazwy funkcji z pewnością nie są.
Steve Cox

1
@SteveCox "nazwy funkcji z pewnością nie są." W końcu są. Tylko liczba ziaren piasku :-P ...
πάντα ῥεῖ

3
ok, ale poważnie. po kompilacji kod obiektowy nadal zawiera nazwy funkcji. inaczej linkowanie nie zadziała
Steve Cox

4
@ πάνταῥεῖ: O ile nie podejmiesz specjalnych starań, aby je usunąć, nazwy funkcji pozostaną w końcowym pliku wykonywalnym.
Nick Matteo

1
@Kundor: Po połączeniu w systemie Windows wszystkie funkcje inne niż specjalne nie zachowują nazw
Dani


7

Tak, używanie różnych nazw jest bezpieczne.

Osobiście nie polecałbym tego jednak jako tradycyjnego argci argvtak powszechnie znanego i znajomego każdego innego programisty C, który mógłby kiedykolwiek pracować z Twoim kodem. Na dłuższą metę używanie własnych, specjalnych, różnych nazw spowoduje znacznie więcej zamieszania i / lub frustracji wśród czytelników, niż kiedykolwiek cię uratuje, ponieważ bardziej lubisz swoje imiona.

"Jeśli wejdziesz między wrony, musisz krakać jak i one."


Jednak istnieje kilka całkiem oczywistych scenariuszy wzywających do używania różnych nazw, znany z nich to inicjalizacja GLUT, glutInit(&argc, argv)w której argumenty muszą być deklarowane i inicjalizowane w inny sposób, aby nie pozwolić, aby GLUT pochłonął argumenty wiersza poleceń, chyba że tego chcemy. SO link
user3078414

@ user3078414 Ciekawy przykład, ale nie rozumiem, jak mówi cokolwiek o tym, jakie zmienne mają być nazwane. Korzystając z przykładów w tym drugim pytaniu, moglibyśmy równie łatwo napisać int dummyargc = 1; char *dummyargv[1] = {(char*)"Something"}; glutInit(&dummyargc, dummyargv);.
Steve Summit

Dzięki, @ steve-summit. Część dokumentacji API jest myląca, dlatego ten wątek jest najbardziej pomocny w podkreślaniu argc argvkonwencji nazewnictwa, podobnie jak twoja odpowiedź. Po prostu umieściłem mój komentarz jako przykład, najlepiej używając różnych nazw. Oto link SO
user3078414

5

Tak, możesz zmienić ich nazwy, jak chcesz. Są to po prostu nazwy parametrów funkcji, nic więcej.


3

Wydaje mi się, że wszyscy dobrze i dobrze omówili techniczne zasady C ++: Odpowiedź brzmi: tak. Odłóżmy na bok tradycję i fakt, że ta 1 szczególna funkcja jest specjalna i ikoniczna, która zawiera ważne punkty, których nie można zmieniać na tej podstawie.

Często wydaje mi się, że filozofia wyborów jest rzadko omawiana i dlatego chciałem przedstawić perspektywę w tej sprawie, ponieważ uważam, że jest to ważne dla powodu, dla którego o to poproszono.

To pytanie dotyczy ogólnego wyboru wyrażania języka angielskiego w kodzie. Wydaje się, że przeszkadzają ci krótkie opisy rąk, w szczególności, jeśli krótkie rozdanie kończy się podobnie wyglądającym tekstem. Jednak w twoim przykładzie zmiana argn na n_of_args powoduje tylko zmianę jednego typu krótkiej ręki na inną formę skrótu bez rzeczywistego dodawania wartości: wyjaśnienie lub inne widoczne właściwości.

Słowo „liczba” zostało zastąpione literą „n”.

Jeśli zmieniasz nazwę krótkiej ręki za pomocą filozofii anty-krótkiej ręki, coś takiego może wydawać się bardziej odpowiednie:

main (int argumentCount, char ** argumentVector)

Zawsze myślę o dwóch rzeczach: nazywanie rzeczy według tego, czym są i / lub przez ich domniemane użycie. Nazywanie go argumentVector jest dla mnie zbędne, ponieważ właściwość bycia wektorem wynika z podwójnego pośredniego **. Zatem lepsza długa wskazówka dotycząca tego, jak napisałbym kod, to: ** argumenty.

Niektórzy powiedzieliby, że zmienna o nazwie argumentCount jest zadeklarowana jako liczba całkowita, a liczba nie może być ujemna, ale można mieć wartość ujemną int {unsigned is better}.

I znowu, co to jest i jak jest używane, zaczyna grać w tej interpretacji. Jeśli jest to hrabia, zakładam, że nigdy nie będzie ujemny. W końcu, jak możesz mieć liczbę -2 jabłek. Powiedziałbym, że OWE dwa jabłka. Jeśli jest to liczba, spodziewałbym się, że możliwy będzie przypadek ujemny. Dlatego prawdopodobnie dodatkowe słowo „z” jest dla Ciebie ważne. To i być może liczba, do której odwołuje się kolekcja, implikuje konkretny element, a nie właściwość samej kolekcji. To znaczy: argumentsNumber = 5 implikuje określony argument, ale nie numberOfArguments.

main (int maxArgumentsIndex, char ** arguments).

Eliminuje to niejednoznaczność. Nazywanie go indeksem usuwa negatywną niejednoznaczność wielkości liter, a także opisuje, czym jest i dodatkowo jak z niego korzystać. Z angielskiego sformułowania wynika również, że maksymalna wartość jest wartością bezwzględną i pisanie kodu modyfikującego tę wartość byłoby dziwne (powinno to być const). „argumenty” mają tutaj sens, ponieważ jest w liczbie mnogiej, opisuje, czym jest i jak już powinno być używane. Nawet interpretacja w ten sposób może być niebezpieczna, ponieważ indeks jest równy -1 z Count / NumberOf. 5 argumentów daje maxIndex równy 4 !!

Każda inna funkcja i całkowicie użyłbym:

funkcja void (const unsigned int maxArgumentsIndex, const char ** arguments)

Nie wszystkie sytuacje zasługują na deskryptory z długiej ręki. W rzeczywistości czasami krótkie rozdanie daje większą czytelność, w szczególności w przypadku pisania klas matematycznych, takich jak Vec3f, Matrix, Quaternion itp ... Prawie zawsze będę starał się dopasować język matematyczny, a nie językowy . float x, y, z vrs. float xComponent i tym podobne.

Rozumiem, że to wszystko zależy od stylu, ale świadomość tych wyborów naprawdę pomoże na dłuższą metę. Gwarantuję, że doświadczeni programiści będą się niepokoić, gdy tablice nie są pisane w liczbie mnogiej, ale z drugiej strony main to specjalna proza ​​istnienia;)


2

Zgodnie ze standardami C, tak, możesz zmienić nazwę, nic nie będzie miało wpływu. Jak rozumiem, w języku C domyślne słowa kluczowe / typy / nazwy tokenów zostały zdefiniowane z przeznaczeniem / zastosowaniem, więc w ten sam sposób są zdefiniowane nazwy

argc --> argument count

argv --> argument vector

co ma również sens pod względem użytkowania, więc możesz zmienić na dowolną oczekiwaną nazwę Reserved names

W GCC wykonanie programu rozpoczyna się od nazwy funkcji main , która nie zależy od jego parametrów.

Kiedy piszesz samodzielny program dla mikrokontrolerów, nie musisz zawracać sobie głowy nazwą, mainzamiast tego możesz zdefiniować własną namei zmienić Assembly entry_point, aby wskazywała Twoją funkcję. Zależy to od kompilatora kontrolera i dostępności wstępnie zdefiniowanego kodu źródłowego kontrolera. Zrobiłem to w kontrolerze Freescale pod Code-warrior.

Moja uwaga:

Lepiej jest przestrzegać wspólnych standardów / stylów kodu, aby kod był bardziej widoczny i czytelny


0

Jeśli chodzi o kompilator, jest bezpieczny.

Jedynym problemem, jaki może to spowodować, jest zamieszanie. Osoby czytające Twój kod będą oczekiwać, że te dwie zmienne będą miały swoje standardowe nazwy. Możesz nawet zrobić coś takiego:

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

Ale nie sądzę, żebym musiał mówić, jak zła byłaby to praktyka.


-1

Jeśli nie lubisz nazw zmiennych, dlaczego nie zastąpić ich makrem #define :

#define yourCounterName argc
#define yourVectorName  argv 

Nie podejmiesz żadnego ryzyka i uzyskasz „czyste rozwiązanie”.


To nie są stałe, tylko podstawienie.
David Dunham
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.