Почему я не получаю ошибку конфликтующих типов, когда у функции нет аргументов?

В этом примере я получаю ошибку Conflicting types, как и ожидалось:

#include <stdio.h>

int a(int b);

int a(int *b){
 return 6;
}

int main(){
 return 0;
}

Но не в этом примере:

#include <stdio.h>

int a(int b);

int a(){
 return 6;
}

int main(){
 return 0;
}

Почему второй пример компилируется нормально, хотя объявление и определение a все еще разные?


person Community    schedule 14.06.2020    source источник
comment
В определении a говорится «любое количество параметров», что, я думаю, вполне приемлемо.   -  person Fredrik    schedule 14.06.2020
comment
также во втором примере вы получите ошибку: переопределение 'a', и это потому, что C не поддерживает перегрузку (за исключением случаев, когда вы компилируете его с помощью компилятора C++, который поддерживает перегрузку)   -  person Alberto Sinigaglia    schedule 14.06.2020
comment
Отвечает ли это на ваш вопрос? Функция C без поведения параметров   -  person Acorn    schedule 14.06.2020
comment
@EricPostpischil скопируйте и вставьте этот код и вместо его объявления реализуйте его, и вы увидите ошибку   -  person Alberto Sinigaglia    schedule 14.06.2020


Ответы (4)


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

См. функцию C без поведения параметров

person Acorn    schedule 14.06.2020

Обзор и история

Из-за истории развития языка C int a() не означает, что «a не принимает аргументов и возвращает int». Это означает, что «a принимает неуказанные аргументы и возвращает int».

Поскольку «неуказанные аргументы» номинально совместимы с «одним аргументом, который является int», компилятор не выдает ошибку для конфликтующих типов. Из-за дополнительных правил в C (см. «Совместимость функций» ниже) типы несовместимы, но компилятор не обязан это диагностировать.

Первоначально в C функции были объявлены со списком параметров (), и вызывающая сторона должна была предоставить правильные типы. (Кроме того, аргументы были «повышены»; аргументы char были преобразованы в int и т. д., но это отдельная проблема.) Если функция была определена, она была определена с именами параметров, такими как int a(b), и объявлениями. следующих параметров, например:

int a()
int b;
{
    return 6*b;
}

Но это было только для определения. В объявлении не было этих объявлений типов параметров.

Позже, чтобы улучшить информацию о типах функций, C добавил грамматику для полных объявлений функций, включая типы параметров, такие как int a(int b). Однако, поскольку старая грамматика уже использовала int a() для обозначения «неуказанных параметров», язык должен был сохранить это значение для поддержки старого кода.

Вместо этого была назначена специальная форма, означающая «без параметров», то есть помещать void в список параметров отдельно. int a(void) означает, что «a — это функция, не принимающая параметров и возвращающая int». Итак, если вы объявите функцию как int a(void);, а затем определите ее как int a(int b) { … }, компилятор выдаст вам сообщение об ошибке.

Совместимость функций

Одно из правил совместимости типов функций в C 2018 6.7.6.3 15 гласит:

… Если один тип имеет список типов параметров, а другой тип указан в определении функции, которое содержит (возможно, пустой) список идентификаторов, оба должны согласоваться по количеству параметров,…

Объявление int a(int b); имеет список типов параметров с одним параметром.

Это определение:

int a(){
 return 6;
}

имеет пустой список идентификаторов и между int a() и { не определяет никаких параметров. Вот и не сошлись в количестве параметров. Однако от компилятора не требуется диагностировать эту несовместимость.

person Eric Postpischil    schedule 14.06.2020

Второй пример:

int a(){ a – это функция, принимающая неопределенное количество параметров. Таким образом, любое число в порядке и, следовательно, нет ошибки.

person 0___________    schedule 14.06.2020

Это дефект компилятора.

Согласно стандарту C (деклараторы функций 6.7.6.3 (включая прототипы))

  1. ...Если один тип имеет список типов параметров, а другой тип указан в определении функции, которое содержит (возможно, пустой) список идентификаторов, оба должны согласоваться по количеству параметров, а тип каждого параметра прототипа должен быть совместим с типом, полученным в результате применения продвижения аргумента по умолчанию к типу соответствующего идентификатора.

Так как в этих декларациях

int a(int b);

int a(){
 return 6;
}

количество параметров отличается для функций, компилятор должен выдать сообщение, потому что имя a используется для объявления двух разных функций.

Например, запустив этот код с помощью gcc 8.3, вы можете получить следующие ошибки.

prog.c: In function ‘a’:
prog.c:5:1: error: number of arguments doesn’t match prototype
 int a(){
 ^~~
prog.c:3:5: error: prototype declaration
 int a(int b);
     ^
person Vlad from Moscow    schedule 14.06.2020