2015-10-24 33 views
14

Przypadek 1:Dlaczego nie ma błędu podczas przekazywania argumentów linii poleceń podczas deklarowania głównego jako `int main (void)`?

void hello(void) { 
    //something 
} 

int main() 
{ 
    hello(1); //error 
    return 0; 
} 

Przypadek 2:

int main(void) { 
    //something 
    return 0; 
} 

Wykonanie:

./a.out something something //No error, Why? 

Dlaczego nie ma błędu? main nie będzie mógł przyjmować żadnych argumentów. Dlaczego więc można podać argumenty z wiersza poleceń?

+0

Dlaczego miałbyś oczekiwać błędu? –

+0

@OliverCharlesworth Ponieważ przekazujemy argument do main? kompilator nie pojawia się w obrazie, ale w czasie wykonywania/wczytywania, dlaczego nie ma błędu? – JagsVG

+2

Powłoka * zawsze * wysyła swoje argumenty do programu - nawet jeśli nie podasz żadnego (zwykle wysyła 'argv [0]'). 'main' nie jest tym samym rodzajem funkcji co' cześć'. – usr2564301

Odpowiedz

14

Ponieważ kompilator języka C i interpreter wiersza poleceń (lub coś, co jest używane do wywoływania programu), są różne.

Język C umożliwia różne sposoby deklarowania funkcji main().

Interpreter wiersza poleceń udostępni wszelkie argumenty programowi. Jeśli program je ignoruje, to nie jest żadna z jego spraw.

Interpreter wiersza poleceń nawet nie wie, że użyłeś C do kompilacji programu. Na moim komputerze program mógł być napisany w językach C, C++, Objective-C, Objective-C++, Swift, Fortran, Ada i innych. Każdy z tych kompilatorów może lub nie może robić rzeczy, aby akceptować polecenia z wiersza poleceń.

9

Nie sprawdzanie specyfikacji ani skompilowany wynik, nie spowoduje błędu, ponieważ środowisko wykonawcze C pobierze argumenty i przekaże je do main(), ale ten typ main() zignoruje przekazane argumenty, a jeśli jest to obowiązkiem osoby wywołującej W górę pamięci (stosu) używanego jako argumenty, nie spowoduje żadnych problemów, tak jak uzyskanie niektórych argumentów i nie używanie ich w kodzie.

Ten kod nie będzie emitować błędów w C:

void hello(); // in C, the compiler won't check arguments 

int main() { 
    hello(1); //no error 
    return 0; 
} 

void hello(void) { 
    //something 
} 
+0

Nigdy nie wiedziałem, że 'void hello(); 'zachowałoby się inaczej niż' void hello (void); 'Interesujące. I nauczyłem się C w 1989 roku. No cóż. –

+0

Wydaje mi się, że masz tu dobry punkt widzenia, ale jest to trochę ukryte: "argumenty" z 'głównego' * nie wymagają czyszczenia stosu *". Czy to jest poprawne? (Oba oznaczały jak przeczytałem to z twojej odpowiedzi i, cóż, tak naprawdę.) – usr2564301

+3

@Jongware Argumenty przekazane do 'main' są czyszczone ze stosu przez funkcję, która * wywołuje *' main', która jest podkładką dostarczoną przez biblioteki C, i ta funkcja nie wie, lub nie obchodzi, jak zadeklarowano 'main'. Nie jest to specjalne dla 'głównego'; jest to normalna konwencja wywoływania C dla wszystkich funkcji. (Rozszerzenia kompilatorów, takie jak '__stdcall', mogą zmienić konwencję, złe rzeczy się zdarzą, jeśli zastosujesz je do' main' - lub jakiejkolwiek innej funkcji wywoływanej przez bibliotekę C.) – zwol

5

./a.out something something Ponieważ nie jest bezpośrednio nazywając swoją główną funkcję. Główna funkcja jest wywoływana przez bibliotekę wykonawczą c. Argumenty wiersza poleceń są umieszczane w regionie gdzieś na stosie (na samym początku) przez środowisko wykonawcze loader/c. To zależy od ciebie, jeśli chcesz uzyskać dostęp do tych argumentów, czy nie.

Dodatkowo, jak wskazano w jednym z komentarzy, co najmniej jeden argument z linii poleceń jest zawsze przekazywany w każdym razie (dokładniej nazwa programu ./a.out) - więc musiałaś zastanawiać się również nad błędem w tym przypadku .

2

Podczas kompilacji programu przy użyciu gcc program_name.c, kompilator zgłosi wszelkie możliwe ostrzeżenia lub błędy dotyczące czasu kompilacji. Ponieważ argumenty wiersza poleceń nie są przekazywane w czasie kompilacji, kompilator nie jest tego świadomy i program po prostu ignoruje te argumenty.

W przypadku hello, kompilator zna prototyp tej funkcji i oczekuje, że w jej wywołaniu nie zostanie przekazany żaden argument, a zatem raportuje błąd w przypadku przekazania jakiegokolwiek argumentu.

+0

@Wybierz wyborcę; Komentarz byłby doceniony? – haccks

3

Przypomnijmy, że ISO C określa dwa możliwe podpisy main: jego int main(void) i int main(int, char *[]) i równoważne wersje, jak int main(int, char **) powodu tablica-do-wskaźnik próchnicy.Jest to bardziej szczegółowo omówione here.

Na to pytanie można odpowiedzieć, rozpatrując przeciwne pytanie: , w jaki sposób środowisko wykonawcze C zna numer main, aby zadzwonić pod numer? C nie ma przeciążeniowej rozdzielczości! Zostało to wyjaśnione here. Krótko mówiąc, pozostałe są popychane, ale nie można do nich dotrzeć, ponieważ C nie jest w stanie tego zrobić.