2014-05-29 28 views
16

Ho problemi a comprendere le funzioni integrate di GCC e mi sento molto confuso.Come GCC gestisce la funzione integrata

  • Qual è la differenza tra una funzione di libreria e una funzione incorporata?

  • C'è qualcosa che una funzione incorporata può fare, ma una funzione di libreria non può?

  • Posso scrivere una funzione di libreria che svolge la stessa funzione della funzione built-in printf? Come posso dire il tipo dei parametri di input (% f, float o double)?

  • Le istruzioni della macchina delle funzioni integrate GCC non sono memorizzate in una libreria, giusto? Dove sono loro?

  • Quando si effettua il collegamento, come è possibile controllare dove inserire questi codici funzione incorporati?

  • Perché a volte riesco a messaggi di errore del tipo "undefined reference to __builtin_stdarg_start" quando si fa il collegamento

    // main.c 
    #include <stdio.h> 
    int main(void) { 
        printf("hello world!\n"); 
        return 0; 
    } 
    

    gcc -c main.c, nm mostra che non v'è alcun printf simbolo main.o, (solo main (T) e puts (U)), perché?

+0

(Si chiama built-in con una T) –

+1

È possibile creare il proprio printf. Guarda l'intestazione di stdargs.h. – Mabus

+2

GCC è (molto probabilmente) l'ottimizzazione di 'printf()' in 'puts()' perché stai passando una semplice stringa a 'printf()' senza ulteriori argomenti. Vedi: http://linux.die.net/man/3/puts – Thomas

risposta

18

Qual è la differenza tra una funzione di libreria e una funzione build-in?

Una funzione incorporata è quella che il compilatore ha una certa conoscenza direttamente all'interno del compilatore stesso. Una funzione di libreria è semplicemente quella definita in una libreria. Possono esistere sia una funzione incorporata che una funzione di libreria con lo stesso nome, quindi per il resto delle tue domande tratterò la "funzione di libreria" come "funzione di libreria che non è una funzione incorporata".

C'è qualcosa che una funzione built-in può fare ma una funzione di libreria non può?

Sì. Una funzione built-in può scegliere, per esempio, non per valutare i suoi argomenti:

int main() { 
    int i = 0; 
    __builtin_constant_p (++i); // checks whether ++i is a constant expression 
           // does not evaluate ++i 
    return i; // returns 0 
} 

Questo perché una funzione built-in può essere trasformato dal compilatore in qualcos'altro, che in realtà non ha bisogno di contenere qualsiasi chiamata di funzione.

Posso scrivere una funzione di libreria che esegue lo stesso compito della funzione di stampa in funzione?

C'è una conoscenza integrata di printf, ma per la maggior parte, questo è perfettamente fattibile. Scopri come usare <stdarg.h>.

Come è possibile indicare il tipo di parametri di input (% f, float o double)?

È necessario fidarsi del chiamante affinché la stringa di formato corrisponda agli argomenti rimanenti; non è possibile rilevare qualcosa come il passaggio di un int quando la stringa di formato si aspetta un double. Ma non è necessario gestire la differenza tra float e double, perché è impossibile passare un float a printf: verrà convertito in double (indipendentemente dalla stringa di formato) prima che lo veda lo printf. I requisiti di printf sono stati accuratamente realizzati per evitare qualsiasi necessità di magia del compilatore.

Le istruzioni della macchina delle funzioni GCC build-in non sono memorizzate in una libreria, giusto?

Le chiamate alle funzioni integrate vengono trasformate in fase di compilazione, ma tale trasformazione può essere semplicemente il risultato di una chiamata a una funzione di libreria con lo stesso nome.

Dove sono?

Se la trasformazione viene eseguita in fase di compilazione, non sono disponibili istruzioni sulla macchina. La chiamata viene trasformata in un codice diverso e tale codice viene quindi compilato per produrre istruzioni sulla macchina. Se il risultato è una chiamata a una funzione di libreria, le istruzioni macchina per quella funzione di libreria fanno parte della libreria.

Quando si effettua il collegamento, come è possibile controllare dove inserire questi codici funzione incorporati?

Non capisco cosa intendi qui. Una chiamata a una funzione built-in viene trasformata in fase di compilazione su un codice diverso e tale codice diverso viene quindi compilato come parte della funzione che contiene la chiamata. Sarà messo ovunque verrà messo il resto del codice di quella funzione contenente.

Perché a volte riesco a messaggi di errore del tipo "undefined reference to __builtin_stdarg_start" quando si fa il collegamento

non esiste alcuna funzione built-in __builtin_stdarg_start, nonostante il prefisso __builtin, quindi questo è trattata come una chiamata a una funzione di libreria. Inoltre, non esiste alcuna funzione di libreria __builtin_stdarg_start, quindi il linker lo rileva come un errore.

C'era una funzione incorporata __builtin_stdarg_start, ma è stata rimossa anni fa e il codice non avrebbe mai dovuto usarlo in primo luogo.

gcc -c main.c, nm indica che non vi è alcun simbolo printf in main.o, (solo main (T) e puts (U)), perché?

Ecco perché printf esiste sia come funzione incorporata che come funzione di libreria. La funzione built-in di solito chiama semplicemente la funzione di libreria, ma a volte è possibile fare di meglio, anche nell'esempio. In questo caso, la funzione integrata printf può fornire il risultato corretto senza chiamare la funzione di libreria printf.

6

Ci sono circa due tipi di built-in: quelli che corrispondono a funzioni di libreria standard (malloc, printf e strcpy sono tutti trattati come built-in per impostazione predefinita), e quelli che non hanno una controparte in la libreria standard - pensa a __builtin_expect, a __builtin_prefetch, ecc.

Il primo tipo di built-in sono lì per consentire al compilatore di emettere codice ottimizzato al posto delle chiamate corrispondenti. Conoscendo la semantica interna di ciascuna chiamata dalla libreria standard, il compilatore può decidere di emettere una chiamata alla funzione che risiede nella libreria o di emettere al suo posto una parte di codice generata dall'utente, in modo che la semantica originale sono conservati e il codice funziona meglio.

Il secondo tipo di built-in (detti anche "intrinseci") abilita trucchi e ottimizzazioni difficilmente realizzabili con un pezzo di codice statico che risiede in una libreria. Possono tradurre in suggerimenti alla CPU (__builtin_prefetch, __builtin_expect) o migliorare il linguaggio C con una migliore introspezione in fase di compilazione (__builtin_constant_p, __builtin_types_compatible_p) o fornire un'interfaccia più semplice e indipendente dalla piattaforma per alcune istruzioni specifiche dell'architettura (__builtin_ffs, __builtin_popcount).

Problemi correlati