C поддерживает перегрузку? - PullRequest
53 голосов
/ 28 февраля 2010

Я просто хочу знать, поддерживает ли C перегрузку?Поскольку мы используем системные функции, такие как printf, с разными аргументами.Помоги мне

Ответы [ 9 ]

44 голосов
/ 28 февраля 2010

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

printf работает с использованием функции, называемой varargs. Вы делаете вызов, который выглядит как будто он может быть перегружен:

printf("%d", 12); // int overload?
printf("%s", "hi"); // char* overload?

На самом деле это не так. Существует только одна функция printf, но для ее вызова компилятор использует специальное соглашение о вызовах, где любые аргументы, которые вы предоставляете, последовательно помещаются в стек [*]. printf (или vprintf) проверяет строку формата и использует ее для выработки способа считывания этих аргументов обратно. Вот почему printf не является типобезопасным:

char *format = "%d";
printf(format, "hi"); // undefined behaviour, no diagnostic required.

[*] стандарт на самом деле не говорит , что они передаются в стеке, или вообще не упоминают стек, но это естественная реализация.

29 голосов
/ 28 февраля 2010

C не поддерживает перегрузку. (Очевидно, что даже если бы это было так, они не использовали бы это для printf: вам нужен printf для каждой возможной комбинации типов!)

printf использует varargs .

22 голосов
/ 28 февраля 2010

Нет, C не поддерживает перегрузку, но поддерживает Вариативные функции . printf является примером функций Variadic.

8 голосов
/ 28 февраля 2010

Все зависит от того, как вы определяете «поддержку».

Очевидно, что язык C предоставляет перегруженные операторы в базовом языке, поскольку большинство операторов в C имеют перегруженную функциональность: вы можете использовать двоичные + с int, long и с типами указателей.

В то же время C не позволяет вам создавать свои собственные перегруженные функции, и стандартной библиотеке C также приходится прибегать к функциям с разными именами, которые будут использоваться с разными типами (например, abs, fabs, labs и т. Д.).

Другими словами, C имеет некоторую степень перегрузки, жестко запрограммированную в основной язык, но ни стандартной библиотеке, ни пользователям не разрешается делать свою собственную перегрузку.

5 голосов
/ 28 февраля 2010

Нет, C не поддерживает перегрузку. Если вы хотите реализовать перегрузку, аналогичную C ++, вам придется манипулировать именами функций вручную, используя какое-то согласованное соглашение. Например:

int myModule_myFunction_add();
int myModule_myFunction_add_int(int);
int myModule_myFunction_add_char_int(char, int);
int myModule_myFunction_add_pMyStruct_int(MyStruct*, int);
1 голос
/ 05 мая 2015

В стандарте C отсутствует положение о перегрузке оператора; Предложения по его добавлению были отклонены на том основании, что многие системы сборки не имеют возможности для размещения нескольких функций с одинаковым именем. Хотя C ++ может обойти это, например, имеющий

void foo(int);
int foo(char*);
long foo(char *, char **);

компилировать в функции с именами типа v__foo_i, i__foo_pc и l__foo_pc_ppc [компиляторы используют разные соглашения об именах, хотя стандарт C ++ запрещает использование внутренних двойных подчеркиваний в идентификаторах, чтобы позволить компиляторам давать имена вещей, подобные приведенным выше, без конфликта ]. Авторы стандарта C не хотели требовать, чтобы какие-либо компиляторы изменили соглашения об именах, чтобы разрешить перегрузку, поэтому они не предусматривают это.

Было бы возможно и полезно для компилятора разрешить перегрузку статических и встроенных функций без создания проблем с именами; на практике это было бы так же полезно, как и перегрузка внешне-связываемых функций, поскольку можно иметь заголовочный файл:

void foo_zz1(int);
int foo_zz2(char*);
long foo_zz3(char *, char **);
inline void foo(int x) { foo_zz1(x); }
inline int foo(char* st) { foo_zz2(st); }
long foo(char *p1, char **p2) { foo_zz3(p1,p2); }

Я вспоминаю, как смотрел на встроенный компилятор для гибрида между C и C ++, который поддерживал вышеупомянутое как нестандартное расширение, но я не уверен в деталях. В любом случае, даже если некоторые компиляторы C поддерживают перегрузку функций, которые не имеют внешней связи, это не поддерживается C14, и я не знаю (к сожалению) каких-либо активных попыток добавить такую ​​функцию в будущие стандарты C.

Тем не менее, GCC может быть сделан с использованием макросов для поддержки формы перегрузки, которая не поддерживается напрямую в языках с перегрузкой операторов. GCC включает в себя встроенную функцию, которая будет определять, может ли выражение быть оценено как константа времени компиляции. Используя эту встроенную функцию, можно написать макрос, который может оценивать выражение различными способами (в том числе путем вызова функций) в зависимости от аргумента. Это может быть полезно в некоторых случаях, когда формула будет оцениваться как константа времени компиляции, если дан аргумент константы времени компиляции, но приведет к ужасному беспорядку, если дан аргумент переменной. В качестве простого примера, предположим, что кто-то хочет перевернуть 32-битное значение. Если значение постоянное, это можно сделать с помощью:

#define nyb_swap(x) \
  ((((x) & 1)<<3) | (((x) & 2)<<1) | (((x) & 4)>>1) | ((((x) & 8)>>3) )
#define byte_swap(x) \
  ( (nyb_swap(x)<<4) | nyb_swap((x) >> 4) )
#define word_swap(x) \
  ( (byte_swap(x)<<24) | (byte_swap((x) >> 8)<<16) | \
    (byte_swap((x) >> 16)<<8) | (byte_swap((x) >> 24)) )

И выражение типа uint32_t x=word_swap(0x12345678); просто загрузит x с 0x87654321. С другой стороны, если значение не является константой, результат будет ужасным: выражение типа uint32_t y=word_swap(x); может генерировать множество десятков инструкций; вызов функции с частично развернутым циклом будет почти таким же быстрым, но намного более компактным. С другой стороны, использование цикла предотвратит рассмотрение результата как константы времени компиляции.

Используя GCC, можно определить макрос, который будет использовать макрос, дающий константу, если ему присвоена константа, или вызвать функцию, если ему дана переменная:

#define wswap(x) \
  (__builtin_constant_p((x)) ? word_swap((x)) : word_swap_func((x))

Этот подход не может сделать все, что может сделать перегрузка на основе типов, но он может сделать многое из того, что перегрузка не может.

1 голос
/ 28 февраля 2010

Не напрямую, и это не так, как printf работает, но возможно создать эквивалент перегруженных функций с помощью макросов, если типы имеют разные размеры. Типовые математические функции в tgmath.h стандарта C99 могут быть реализованы таким образом.

0 голосов
/ 28 февраля 2010

Нет c не поддерживает перегрузку функций. Но вы можете заставить его скомпилировать / работать, если вы используете g ++ (компилятор c ++).

0 голосов
/ 28 февраля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...