объявление функции не является прототипом

158

У меня есть библиотека, которую я создал,

mylib.c:

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

mylib.h:

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

В моей программе я попытался вызвать эту библиотечную функцию:

myprogram.c:

#include <mylib.h>

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

Когда я пытаюсь скомпилировать эту программу, я получаю следующую ошибку:

В файле из myprogram.c: 1
mylib.h: 2 предупреждение: объявление функции не является прототипом

Я использую: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)

У меня вопрос, как правильно объявить прототип функции?

Алан Х
источник
1
Удалите extern из объявления в mylib.h. Особенно, если вы пишете программу на чистом C, там нет необходимости в объявлении extern.
Райан Ахерн

Ответы:

333

В Си int foo()и int foo(void)есть разные функции. int foo()принимает произвольное количество аргументов, в то время как int foo(void)принимает 0 аргументов. В C ++ они означают одно и то же. Я предлагаю вам использовать voidпоследовательно, когда вы имеете в виду без аргументов.

Если у вас есть переменная a, extern int a;это способ сообщить компилятору, что aэто символ, который может присутствовать в другом модуле перевода (компилятор C говорит об исходном файле), не разрешайте его до времени ссылки. С другой стороны, символы, которые являются именами функций, в любом случае разрешаются во время соединения. Значение спецификатора класса хранения для функции ( extern, static) влияет только на ее видимость и externявляется значением по умолчанию, поэтому externфактически не является необходимым.

Я предлагаю удалить extern, это постороннее и обычно опускается.

Pramod
источник
9
Используйте (void) в C, чтобы указать, что функция не принимает аргументов. В C ++, если вам не нужен ваш код для компиляции как в C, так и в C ++, просто используйте ().
Кит Томпсон
49

Быстрый ответ: измените int testlib()на, int testlib(void)чтобы указать, что функция не принимает аргументов.

Прототип , по определению , объявление функции , которая определяет тип (ы) аргумент функции (ы).

Объявление функции без прототипа, например

int foo();

это объявление старого стиля, в котором не указывается количество или типы аргументов. (До стандарта ANSI C 1989 года это было единственное объявление функции, доступное на языке.) Вы можете вызывать такую ​​функцию с любым произвольным числом аргументов, и компилятор не должен жаловаться - но если вызов несовместим с определением , ваша программа имеет неопределенное поведение.

Для функции, которая принимает один или несколько аргументов, вы можете указать тип каждого аргумента в объявлении:

int bar(int x, double y);

Функции без аргументов являются особым случаем. Логически, пустые скобки были бы хорошим способом указать, что аргумент, но этот синтаксис уже используется для объявлений функций старого стиля, поэтому комитет ANSI C изобрел новый синтаксис, используя voidключевое слово:

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

Функция определения (которая включает в себя код для того, что на самом деле делает функция) также предоставляет декларацию . В вашем случае у вас есть что-то похожее на:

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

Это обеспечивает объявление не-прототипа для testlib. Как определение, это говорит компилятору, что у testlibнего нет параметров, но как объявление, это только говорит компилятору, который testlibпринимает неуказанное, но фиксированное число и тип (ы) аргументов.

При изменении ()в (void)декларации становится прототипом.

Преимущество прототипа состоит в том, что если вы случайно вызовете testlibодин или несколько аргументов, компилятор диагностирует ошибку.

(C ++ имеет немного другие правила. C ++ не имеет объявлений функций старого стиля, и пустые скобки специально означают, что функция не принимает аргументов. C ++ поддерживает (void)синтаксис для согласованности с C. Но если вам не нужен ваш код для компиляции как C и C ++, вы, вероятно, должны использовать ()в C ++ и (void)синтаксис в C.)

Кит Томпсон
источник
22

Пытаться:

extern int testlib(void);
Лассе В. Карлсен
источник