2009-10-18 13 views

Odpowiedz

56

To składnia starym stylu dla list parametrów, które nadal są obsługiwane. W K & R C można również pominąć deklaracje typu i domyślnie int. tj.

main(argc, argv) 
char *argv[]; 
{ 
    return 0; 
} 

będzie taką samą funkcją.

+13

Zarówno C89/90, jak i C99 nadal oficjalnie wspierają deklaracje stylu K & R. Jednak w C99 wszystkie parametry muszą być jawnie zadeklarowane (nie ma już reguły "implicit int"). – AnT

+1

Nie znoszę spóźnić się na imprezę (jak 4 lata później?), Ale czy chcesz powiedzieć, że w C99 muszą być jawnie zadeklarowane * na liście parametrów * lub * w funkcji *? Na przykład, domyślna reguła int - ponieważ nie są już domyślne int, to ich typy muszą być zadeklarowane w funkcji przed użyciem ** jeśli ** typy nie zostały podane na liście parametrów? –

+1

@ChrisCirefice Aby odpowiedzieć Ci 4 lata później: w C99 wszystkie parametry muszą być zadeklarowane na liście parametrów. Zmienne zadeklarowane w funkcji nigdy nie miały domyślnego "int", a zatem muszą być jawnie zadeklarowane. –

3

Nie ma różnicy, po prostu jest to stara składnia deklaracji funkcji w C - była używana przed ANSI. Nigdy nie pisz tego kodu, chyba że masz zamiar dać go znajomym z lat 80.. Ponadto, nigdy nie zależy od domyślnych założeń typu (jak sugeruje inna odpowiedź)

+0

Well pre C99; był używany przed ANSI, który został ujednolicony w 1989 r., ale proces rozpoczął się w 1983 r. –

+0

Dzięki mate. Naprawiono to teraz ... – aviraldg

+1

Ahem ... Deklaracje w stylu K & R są nadal oficjalnie wspierane przez C99, z jedną drobną zmianą - bez "ukrytego int", wszystkie parametry muszą być jawnie zadeklarowane. – AnT

1

To jest to samo, ale stare podejście. Prawdopodobnie znalazłeś jakiś stary, starszy kod.

4

Podczas gdy stara składnia definicji funkcji nadal działa (z ostrzeżeniami, jeśli pytasz swojego kompilatora), używanie ich nie zapewnia prototypów funkcji.
Bez prototypów funkcji kompilator nie sprawdza, czy funkcje są poprawnie wywoływane.

#include <stdio.h> 
int foo(c) 
int c; 
{ return printf("%d\n", c); } 

int bar(x) 
double x; 
{ return printf("%f\n", x); } 

int main(void) 
{ 
    foo(42); /* ok */ 
    bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */ 
    return 0; 
} 

Gdy program jest uruchomiony, wyjście na moim komputerze jest

$ gcc proto.c 
$ gcc -Wstrict-prototypes proto.c 
proto.c:4: warning: function declaration isn’t a prototype 
proto.c:10: warning: function declaration isn’t a prototype 
$ ./a.out 
42 
0.000000 
10

Jest to tak rozmówcy K & R Style lub starym stylu deklaracja.

Należy zauważyć, że ta deklaracja jest znacząco inna niż nowoczesna deklaracja. K & Deklaracja R nie wprowadza do funkcji prototypu, co oznacza, że ​​nie wystawia ona typów parametrów na kod zewnętrzny.

24

Co równie interesująca jest różnica w wywoływaniu funkcji i funkcji bez prototypu. Rozważmy starą definicję styl:

void f(a) 
float a; { 
/* ... */ 
} 

w tym przypadku konwencja powołaniem jest to, że wszystkie argumenty są promowane przed przekazany do funkcji. Jeśli więc f odbiera double, ale parametr ma typ float (który jest całkowicie poprawny), kompilator musi emitować kod, który konwertuje double do float przed wykonaniem treści funkcji.

Jeśli dołączyć prototyp, kompilator nie wykonuje już takich automatycznych promocji, a wszelkie przekazane dane są konwertowane na typy parametrów prototypu, jak przy przydziale.Więc dodaje nie jest legalne i wyniki w niezdefiniowanej zachowań:

void f(float a); 
void f(a) 
    float a; { 

} 

W tym przypadku definicja danej funkcji byłoby przekształcić przekazany parametr z double (forma promocji) do float ponieważ definicja jest w starym stylu. Ale parametr został przesłany jako float, ponieważ funkcja ma prototyp. Opcje rozwiązywania sprzeczności są dwa następujące:

// option 1 
void f(double a); 
void f(a) 
    float a; { 

} 

// option 2 
// this declaration can be put in a header, but is redundant in this case, 
// since the definition exposes a prototype already if both appear in a 
// translation unit prior to the call. 
void f(float a); 

void f(float a) { 

} 

Opcja 2 powinny być preferowane, jeśli masz wybór, ponieważ pozbywa definicji starym stylu z przodu. Jeśli takie sprzeczne typy funkcji dla funkcji pojawiają się w tej samej jednostce tłumaczeniowej, kompilator zwykle powie ci (ale nie jest to wymagane). Jeśli takie sprzeczności pojawią się w wielu jednostkach tłumaczeniowych, błąd prawdopodobnie pozostanie niezauważony i może spowodować trudne do przewidzenia błędy. Najlepiej unikać tych starych definicji stylu.

Powiązane problemy