declaração de função não é um protótipo

158

Eu tenho uma biblioteca que eu criei,

mylib.c:

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

mylib.h:

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

No meu programa, tentei chamar esta função de biblioteca:

myprogram.c:

#include <mylib.h>

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

Quando tento compilar este programa, recebo o seguinte erro:

No arquivo incluído em myprogram.c: 1
mylib.h: 2 aviso: declaração de função não é um protótipo

Estou a usar: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

Minha pergunta é: qual é a maneira correta de declarar um protótipo de função?

Alan H
fonte
1
Remova extern da declaração em mylib.h Especialmente se você estiver escrevendo um programa C puro, a declaração extern é desnecessária.
Ryan Ahearn

Respostas:

333

Em C int foo()e int foo(void)são diferentes funções. int foo()aceita um número arbitrário de argumentos, enquanto int foo(void)aceita 0 argumentos. Em C ++, eles significam a mesma coisa. Eu sugiro que você use voidconsistentemente quando não quer dizer argumentos.

Se você tiver uma variável a, extern int a;é uma maneira de dizer ao compilador que aé um símbolo que pode estar presente em uma unidade de tradução diferente (o compilador C fala pelo arquivo de origem), não o resolva até o tempo do link. Por outro lado, os símbolos que são nomes de funções são resolvidos de qualquer maneira no momento do link. O significado de um especificador de classe de armazenamento em uma função ( extern, static) afeta apenas sua visibilidade e externé o padrão, portanto, externé realmente desnecessário.

Sugiro remover o extern, é estranho e geralmente é omitido.

Pramod
fonte
9
Use (void) em C para indicar que uma função não aceita argumentos. No C ++, a menos que você precise especificamente do seu código para compilar como C e C ++, basta usar ().
Keith Thompson
49

Resposta rápida: altere int testlib()para int testlib(void)para especificar que a função não aceita argumentos.

Um protótipo é, por definição, uma declaração de função que especifica o (s) tipo (s) do (s) argumento (s) da função.

Uma declaração de função não protótipo como

int foo();

é uma declaração de estilo antigo que não especifica o número ou os tipos de argumentos. (Antes do padrão ANSI C de 1989, esse era o único tipo de declaração de função disponível no idioma.) Você pode chamar essa função com qualquer número arbitrário de argumentos, e o compilador não precisa se queixar - mas se o Se a chamada for inconsistente com a definição , seu programa tem um comportamento indefinido.

Para uma função que recebe um ou mais argumentos, você pode especificar o tipo de cada argumento na declaração:

int bar(int x, double y);

Funções sem argumentos são um caso especial. Logicamente, parênteses vazios teriam sido uma boa maneira de especificar esse argumento, mas essa sintaxe já estava sendo usada para declarações de função de estilo antigo; portanto, o comitê ANSI C inventou uma nova sintaxe usando a voidpalavra-chave:

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

Uma definição de função (que inclui código para o que a função realmente faz) também fornece uma declaração . No seu caso, você tem algo semelhante a:

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

Isso fornece uma declaração sem protótipo para testlib. Como definição, isso informa ao compilador que testlibnão possui parâmetros, mas como declaração, ele diz apenas ao compilador que testlibutiliza algum número e tipo (s) de argumentos não especificados, mas fixos.

Se você mudar ()para (void)a declaração, torna-se um protótipo.

A vantagem de um protótipo é que, se você chamar acidentalmente testlibcom um ou mais argumentos, o compilador diagnosticará o erro.

(O C ++ possui regras ligeiramente diferentes. O C ++ não possui declarações de função no estilo antigo, e parênteses vazios significam especificamente que uma função não aceita argumentos. O C ++ suporta a (void)sintaxe da consistência com C. Mas, a menos que você precise especificamente do seu código para compilar os dois, C e como C ++, você provavelmente deve usar o ()em C ++ e a (void)sintaxe em C.)

Keith Thompson
fonte
22

Experimentar:

extern int testlib(void);
Lasse V. Karlsen
fonte