deklaracja funkcji nie jest prototypem


158

Mam utworzoną przeze mnie bibliotekę,

mylib.c:

#include <mylib.h>
int
testlib() {
    printf("Hello world\n");
    return (0);
}

mylib.h:

#include <stdio.h>
extern int testlib();

W moim programie próbowałem wywołać tę funkcję biblioteczną:

myprogram.c:

#include <mylib.h>

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

Kiedy próbuję skompilować ten program, pojawia się następujący błąd:

W pliku zawartym z myprogram.c: 1
mylib.h: 2 ostrzeżenie: deklaracja funkcji nie jest prototypem

Używam: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

Moje pytanie brzmi: jaki jest właściwy sposób zadeklarowania prototypu funkcji?


1
Usuń extern z deklaracji w mylib.h Szczególnie jeśli piszesz czysty program w C, deklaracja extern jest tam niepotrzebna.
Ryan Ahearn,

Odpowiedzi:


333

W C int foo()i int foo(void)są różne funkcje. int foo()akceptuje dowolną liczbę argumentów, a int foo(void)akceptuje 0 argumentów. W C ++ mają na myśli to samo. Sugeruję, abyś używał voidkonsekwentnie, gdy nie masz na myśli żadnych argumentów.

Jeśli masz zmienną a, extern int a;jest to sposób, aby powiedzieć kompilatorowi, że ajest to symbol, który może być obecny w innej jednostce tłumaczenia (kompilator C mówi o pliku źródłowym), nie rozwiązuj go do czasu połączenia. Z drugiej strony symbole, które są nazwami funkcji, są i tak rozwiązywane w czasie łączenia. Znaczenie specyfikatora klasy pamięci w funkcji ( extern, static) wpływa tylko na jej widoczność i externjest wartością domyślną, więc w externrzeczywistości jest niepotrzebne.

Sugeruję usunięcie extern, jest to obce i zwykle jest pomijane.


9
Użyj (void) w C, aby wskazać, że funkcja nie przyjmuje argumentów. W C ++, chyba że potrzebujesz kodu do kompilacji zarówno jako C, jak i C ++, po prostu użyj ().
Keith Thompson,

49

Szybka odpowiedź: zmień int testlib()na, int testlib(void)aby określić, że funkcja nie przyjmuje argumentów.

Prototyp jest z definicji deklaracja funkcja, która określa typ (y) argumentów danej funkcji (S).

Nie-prototypowa deklaracja funkcji, taka jak

int foo();

jest deklaracją w starym stylu, która nie określa liczby ani typów argumentów. (Przed standardem ANSI C z 1989 r. Był to jedyny rodzaj deklaracji funkcji dostępny w tym języku). Możesz wywołać taką funkcję z dowolną liczbą argumentów, a kompilator nie musi narzekać - ale jeśli call jest niezgodne z definicją , Twój program ma niezdefiniowane zachowanie.

W przypadku funkcji, która przyjmuje jeden lub więcej argumentów, możesz określić typ każdego argumentu w deklaracji:

int bar(int x, double y);

Funkcje bez argumentów są przypadkiem specjalnym. Logicznie rzecz biorąc, puste nawiasy byłyby dobrym sposobem określenia tego argumentu, ale ta składnia była już używana w deklaracjach funkcji w starym stylu, więc komitet ANSI C wymyślił nową składnię za pomocą voidsłowa kluczowego:

int foo(void); /* foo takes no arguments */

Definicja funkcji (która zawiera kod określający, co funkcja faktycznie robi) również zawiera deklarację . W twoim przypadku masz coś podobnego do:

int testlib()
{
    /* code that implements testlib */
}

Zapewnia to deklarację nie będącą prototypem testlib. Z definicji mówi to kompilatorowi, że testlibnie ma parametrów, ale jako deklaracja mówi kompilatorowi tylko, że testlibpobiera nieokreśloną, ale stałą liczbę i typ (y) argumentów.

Po zmianie ()do (void)deklaracji staje się prototypem.

Zaletą prototypu jest to, że jeśli przypadkowo wywołasz testlibjeden lub więcej argumentów, kompilator zdiagnozuje błąd.

(C ++ ma nieco inne zasady. C ++ nie posiada deklaracje funkcji w starym stylu i pustych nawiasów konkretnie oznacza to, że funkcja przyjmuje żadnych argumentów. C ++ obsługuje (void)składni dla spójności z C. Ale chyba specjalnie potrzebny jest kod do kompilowania zarówno jako C i jako C ++ powinieneś prawdopodobnie użyć ()w C ++ i (void)składni w C.)


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.