Можете ли вы сделать перегрузку в C и иметь то же имя функции? - PullRequest
1 голос
/ 26 апреля 2020

В Java мы можем сделать перегрузку, когда метод имеет то же имя. И я гуглил, и там говорилось, что C не поддерживает перегрузку, поэтому мне было интересно, есть ли способ сделать что-то похожее на перегрузку в C.

Например:

int max(int num1, int num2);
double max(double num1, num2);

int main(){
  printf(...);
  printf(...);
}

int max(int num1, int num2){
  ...
}

double max(double num1, double num2){
  ...
}

1 Ответ

8 голосов
/ 26 апреля 2020

Ссылка, которую вы нашли, верна: C не поддерживает перегрузку, как таковую.

Что она имеет (если мы говорим о реальных C, а не исторических c версиях ) является универсальным селектором c, который позволяет вам написать собственный макрос, который выполняет динамическую c диспетчеризацию.

C99 представил заголовок tgmath.h, который допускает определенные математические функции быть перегруженным для использования с аргументами с плавающей запятой различной ширины, а в некоторых случаях со сложными аргументами. Однако в C99 не было введено ни одного средства, позволяющего обобщить эту функцию для других функций. Селектор generi c, представленный в C11, является этим средством.

Селектор имеет форму _Generic(select-expression, type-associations), где type-associations состоит из разделенного запятыми списка пар вида type : expression. Селектор будет заменен выражением, соответствующим типу select-expression. Одним из type s может быть ключевое слово default; остальные должны быть уникальными полными типами (т. е. никакие два типа в списке не могут быть совместимы) [Примечание 1]. Важно отметить, что все выражений в списке ассоциаций должны компилироваться без ошибок, а не только выбранное. Обычно выражения будут указателями на функции, а не на вызовы функций.

Пример может прояснить это. Предположим, у нас есть две функции (которые имеют разные имена, поэтому это не перегрузка имен):

int max_int(int a, int b) { return a > b ? a : b; }
double max_dbl(double a, double b) { return a > b ? a : b; }

Теперь мы можем определить макрос MAX:

#define MAX(a, b) _Generic((a)+(b),          \
                    int : max_int,           \
                    double : max_dbl)(a, b)

Здесь я используйте a+b в качестве выражения селектора, а не a, потому что тип a+b - это тип, который получается в результате обычных арифметических c преобразований. Если бы я просто использовал a, то MAX(3, 5.7) дал бы неожиданный результат, потому что селектор generi c выбрал бы max_int, а 5.7 был бы тихо обрезан до 5. С a+b, тип селектора будет double, что приведет к вызову max_dbl, для которого оба значения будут преобразованы в удвоение.

Я могу избежать использования (a)+(b) в макросе, потому что _Generic не оценивает выражение селектора (например, sizeof). Таким образом, нет опасности двойной оценки аргументов с побочными эффектами.


Примечания:

  1. Тип обобщенной c ассоциации не может быть VLA (массив переменной длины), даже если компилятор их реализует. Но с любым другим полным типом все в порядке, даже указатель на неполный тип.
...