2010-02-28 17 views
50

Voglio solo sapere se C supporta il caricamento? Poiché utilizziamo funzioni di sistema come printf con diverso no di argomenti. Help meIl C supporta il sovraccarico?

+2

Duplicato: http://stackoverflow.com/questions/479207/funzionamento-overloading-in-c –

+0

Vedere la risposta di Leushenko del 2014 utilizzando il selettore di tipo C11 _Generic nel dupe http://stackoverflow.com/questions/479207/function -overloading-in-c. –

risposta

44

No, C non supporta alcuna forma di sovraccarico (se non si considera il fatto che gli operatori incorporati sono sovraccaricati già, ad essere una forma di sovraccarico).

printf funziona utilizzando una funzionalità chiamata varargs. Si effettua una chiamata che sembra come esso potrebbe essere troppo carico:

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

In realtà non lo è. Esiste solo una funzione printf, ma il compilatore usa una convenzione di chiamata speciale per chiamarla, dove qualunque argomento tu fornisci viene messo in sequenza sullo stack [*]. printf (o vprintf) esamina la stringa di formato e la usa per capire come leggere quegli argomenti indietro. Questo è il motivo per cui printf non è il tipo di sicurezza:

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

[*] la norma in realtà non dicono stanno passati sullo stack, o parlare di una pila a tutti, ma questo è l'implementazione naturali .

+0

Non posso parlare per tutti i compilatori, ma quello con cui lavoro ha il chiamante regolare lo stack per gli argomenti che ha spinto, una volta che la funzione ritorna. Questa mi sembra una buona idea per le funzioni variadiche, più sicuro che avere la funzione per farle scoppiare. – tomlogic

+1

Hai ragione, in realtà la convenzione chiamata cdecl funziona esattamente come quella (il chiamante è responsabile della pulizia dello stack); Ho eliminato il commento per evitare di confondere altri lettori. Il vero problema è con scanf, che, se fornite una stringa di formato errata, può scrivere i dati in posizioni casuali (presi dallo stack) in memoria. –

+0

C1X supporterà tramite espressioni generiche di tipo e macro – Spudd86

29

C non supporta il sovraccarico. (Ovviamente, anche se lo facesse, non lo userebbero per printf: avresti bisogno di un printf per ogni possibile combinazione di tipi!)

printf utilizza varargs.

0

C Non supporta il sovraccarico. Ma possiamo implementare questa funzionalità programmando la nostra libreria che a sua volta potrebbe fornire supporto per il sovraccarico.

+2

Non sai cosa intendi. Come sarebbe una libreria che fornisce supporto per il sovraccarico? – sepp2k

+1

@ sepp2k, un gruppo di tabelle di puntatori a funzioni. –

+0

@Carl: Sembra che tu stia parlando di un vtable. Questo è per ereditarietà, non sono sicuro di come ciò possa essere d'aiuto con il sovraccarico. – sepp2k

5

No, C non supporta il sovraccarico. Se vuoi implementare un sovraccarico simile a C++, dovrai manipolare i nomi delle funzioni manualmente, usando una sorta di convenzione coerente. Ad esempio:

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); 
8

Tutto dipende da come si definisce "supporto".

Ovviamente, il linguaggio C fornisce operatori di overload all'interno del linguaggio di base, dal momento che la maggior parte degli operatori di C hanno sovraccaricato funzionalità: è possibile utilizzare binari + con int, long e con tipi di puntatore.

Eppure, allo stesso tempo C non consente di creare i propri funzioni sovraccaricate e C libreria standard ha anche ricorrere a funzioni diversamente denominate per essere utilizzato con diversi tipi (come abs, fabs, labs e così via).

In altre parole, C ha un certo grado di sovraccarico hardcoded nel linguaggio di base, ma né la libreria standard né gli utenti sono autorizzati a eseguire il proprio overloading.

-5

No c non supporta il sovraccarico delle funzioni. Ma puoi farlo compilare/lavorare se stai usando g ++ (un compilatore C++).

+3

-1, se stai scrivendo C dovresti usare un compilatore C. –

+4

Secondato. Se stai usando un compilatore C++ per compilare il tuo codice, quello che stai scrivendo è codice C++, non codice C. Soprattutto se stai usando funzionalità di C++ che non sono in C, come il sovraccarico di funzioni! –

+0

seriamente -2 haha – chinmaya

1

Non direttamente, e questo non è il modo in cui funziona printf, ma è possibile creare l'equivalente di funzioni sovraccaricate utilizzando macro se i tipi sono di dimensioni diverse. Le funzioni matematiche di tipo generico in tgmath.h dello standard C99 possono essere implementate in questo modo.

1

Non vi è alcuna disposizione nello standard C per il sovraccarico dell'operatore; le proposte per aggiungerlo sono state respinte sulla base del fatto che molti sistemi di generazione non hanno la possibilità di ospitare più funzioni con lo stesso nome. Mentre C++ può aggirare questo, ad es. avendo

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

compilare alle funzioni di un nome simile a v__foo_i, i__foo_pc e l__foo_pc_ppc [compilatori utilizzano diversi convenzioni di denominazione, anche se il C++ standard di vieta l'uso di doppi sottolineatura interni in identificatori in modo da consentire compilatori di dare nomi cose come sopra senza conflitto]. Gli autori dello standard C non volevano richiedere a nessun compilatore di modificare le convenzioni di denominazione per consentire il sovraccarico, quindi non lo prevedono.

Sarebbe possibile e utile per un compilatore consentire l'overloading di funzioni statiche e inline senza creare problemi di denominazione; questo risulti effettivamente utile quanto consente sovraccarico di funzioni esternamente correlabili poiché si potrebbe avere un file di intestazione:

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); } 

Ricordo guardando un compilatore embedded per un ibrido tra C e C++ che ha sostenuto quanto sopra come un'estensione non standard, ma non sono favorevole ai dettagli. In ogni caso, anche se alcuni compilatori C supportano l'overloading di funzioni che non hanno un collegamento esterno, non è supportato da C14 né sono a conoscenza (purtroppo) di alcuno sforzo attivo per aggiungere tale funzionalità ai futuri standard C.

Ciononostante, è possibile creare GCC, utilizzando macro, per supportare un tipo di sovraccarico che non è supportato direttamente nelle lingue con sovraccarico dell'operatore. GCC include un'intrinseca che identificherà se un'espressione può essere valutata come costante in fase di compilazione. Usando questo intrinseco, si può scrivere una macro che può valutare un'espressione in modi diversi (anche chiamando funzioni) a seconda dell'argomento. Questo può essere utile in alcuni casi in cui una formula valuterà come costante in fase di compilazione se fornita di un argomento costante in fase di compilazione, ma produrrebbe un pasticcio orribile se viene fornito un argomento variabile. Come semplice esempio, si supponga che si desideri reindirizzare a bit un valore a 32 bit. Se il valore è costante, si potrebbe fare che tramite:

#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))) 

E un'espressione come uint32_t x=word_swap(0x12345678); sarebbe semplicemente caricare x con 0x87654321. D'altra parte, se il valore non è una costante, il risultato sarebbe orribile: un'espressione come uint32_t y=word_swap(x); potrebbe generare molte dozzine di istruzioni; una chiamata a una funzione con un ciclo parzialmente srotolato sarebbe quasi altrettanto veloce ma molto più compatta. D'altra parte, l'uso di un ciclo impedirebbe che il risultato venga considerato come una costante in fase di compilazione.

Utilizzando GCC, si può definire una macro che o utilizzare la macro costante rendimento se dato una costante, o chiamare una funzione quando data una variabile:

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

Questo approccio non può fare tipo tutto l'overloading può fare, ma può fare molte cose che l'overloading non può fare.