2013-05-13 13 views
24

Ho bisogno di implementare alcuni metodi che fanno cose con diversi tipi di matrici di numeri. Di solito, userei i generici per quel lavoro, ma dato che C non li fornisce, sto cercando di emularli usando le macro.Pseudo-generici in C

Ecco un esempio di quello che sto cercando di fare:

#ifndef TYPE 
#define TYPE int 
#endif 

TYPE get_minimum_##TYPE (TYPE * nums, int len){ 
    TYPE min = nums[0]; 

    for (int i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

Tuttavia, questo non verrà compilato. Il messaggio di errore clang:

error: expected ';' after top level declarator

C'è un modo per farlo in C? O ho bisogno di implementarlo manualmente per ogni tipo?

+0

fyi generics in C# e java sono una funzionalità di runtime. –

+0

Se vuoi leggere un po 'di più su "templates"/"generics" in C, [puoi leggere questa domanda] (http://stackoverflow.com/questions/10950828/simulation-of-templates-in-c). Ci sono alcune risposte interessanti :) – Jehan

risposta

25

Si può fare qualcosa di simile in un file di intestazione:

// 
// generic.h 
// 

#define TOKENPASTE(x, y) x ## y 

#define GET_MINIMUM(T) TOKENPASTE(get_minimum_, T) 

TYPE GET_MINIMUM (TYPE) (TYPE * nums, size_t len){ 
    TYPE min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

e poi #include in un file sorgente per ogni tipo di richiesta, ad esempio:

// 
// generic.c 
// 

#define TYPE int 
#include "generic.h" 
#undef TYPE 

#define TYPE float 
#include "generic.h" 
#undef TYPE 

È possibile verificare questo eseguendo attraverso il preprocessore:

$ gcc -E generic.c 

int get_minimum_int (int * nums, size_t len){ 
    int min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 

float get_minimum_float (float * nums, size_t len){ 
    float min = nums[0]; 

    for (size_t i = 1; i < len; i++) { 
     if (nums[i] < min) { 
      min = nums[i]; 
     } 
    } 

    return min; 
} 
23

In realtà, il meglio che puoi fare è definire acro che genererà la funzione per il tipo specificato.

#define define_get_minimum(T) \ 
T get_minimum_##T(T* nums, int len){ \ 
    T min = nums[0]; \ 
    for (int i = 1; i < len; i++) { \ 
     if (nums[i] < min) { \ 
      min = nums[i]; \ 
     } \ 
    } \ 
    return min; \ 
} 

Poi, si può chiamare che macro per definire le specializzazioni necessari (con template C++, una cosa simile è fatta automagicamente dal compilatore).

define_get_minimum(int) 
define_get_minimum(double) 
define_get_minimum(float) 

Un'altra cosa che un compilatore C++ fa automaticamente è dedurre la funzione di sovraccarico necessaria. Non puoi averlo in C, quindi dovrai dire che stai usando la specializzazione. È possibile simulare una sintassi modello simile per la vostra funzione con la seguente macro (il C++ <> sono semplicemente sostituiti da ()):

#define get_minimum(T) get_minimum_##T 

Quindi, si dovrebbe essere in grado di chiamare il seguente modo:

int main() 
{ 
    // Define arr as char* array... 
    // Do stuff... 
    int res = get_minimum(int)(arr, 3); 
} 

Non ho testato questo codice, ma dovrebbe funzionare.

+0

+1: l'ho appena testato e sembra funzionare. –

+0

Mi piace lo stile della chiamata finale, ma stavo cercando di archiviarlo senza macro grandi. – fb55

+0

@ fb55 Bene, generico e non grande non sono compatibili in C :) – Jehan

0

È inoltre possibile utilizzare i puntatori di funzione (Array of function pointers) diversi da un'istruzione switch e passare l'argomento dello switch come indice all'array.