2009-08-13 18 views
17

Se ho un prototipo che assomiglia a questo:Come passare un array costante letterale a una funzione che accetta un puntatore senza utilizzare una variabile C/C++?

function(float,float,float,float) 

posso passare valori come questo:

function(1,2,3,4); 

Quindi, se il mio prototipo è questo:

function(float*); 

C'è qualche come posso ottenere qualcosa di simile?

function({1,2,3,4}); 

Solo in cerca di un modo pigro per fare questo senza creare una variabile temporanea, ma io non riesco a inchiodare la sintassi.

+0

Grazie per il consiglio. Suppongo che mi aspettassi risposte veloci e sporche per una domanda veloce e sporca, ma la tua risposta ha esplorato alcuni stili alternativi a cui non avevo pensato. Molto apprezzato! – sinoth

risposta

27

si può fare in C99 (ma non ANSI C (C90) o qualsiasi curr ent variante di C++) con letterali composti. Vedere la sezione 6.5.2.5 dello standard C99 per i dettagli cruenti. Ecco un esempio:

// f is a static array of at least 4 floats 
void foo(float f[static 4]) 
{ 
    ... 
} 

int main(void) 
{ 
    foo((float[4]){1.0f, 2.0f, 3.0f, 4.0f}); // OK 
    foo((float[5]){1.0f, 2.0f, 3.0f, 4.0f, 5.0f}); // also OK, fifth element is ignored 
    foo((float[3]){1.0f, 2.0f, 3.0f}); // error, although the GCC doesn't complain 
    return 0; 
} 

GCC prevede anche questo come estensione di C90. Se si compila con -std=gnu90 (impostazione predefinita), -std=c99 o -std=gnu99, verrà compilato; se si compila con -std=c90, non lo farà.

+0

Si potrebbe ovviamente anche compilare con '-std = gnu89' (ma non' -std = c89'), poiché è anche sinonimo di '-std = gnu90' (e '-std = c90') (Sono sicuro che tu conosci questo Adam, è più per gli altri nel caso in cui non lo facessero: P). – RastaJedi

2

La cattiva notizia è che non esiste una sintassi per questo. La buona notizia è che questo cambierà con la prossima versione ufficiale dello standard C++ (prevista per il prossimo anno o due). La nuova sintassi avrà esattamente lo stesso aspetto che descrivi.

+1

heh heh, il prossimo anno o due:] Buono a sapersi questo sarà in C++ 0x. – sinoth

+0

Dubito in due anni. La beta 10 di Visual Studio ha già alcune funzionalità di C++ 0x, e g ++ 4.4 ha già elenchi di inizializzatori (http://gcc.gnu.org/projects/cxx0x.html). È stato respinto fino al 2010, probabilmente nel primo trimestre. – GManNickG

0

No, non puoi farlo. Non ho lo standard disponibile qui, quindi non posso dare un riferimento esatto, ma la cosa più vicina a quello che chiedi è costanti stringa, cioè

function(char *); 
function("mystring"); 

è trattata dal compilatore come

char * some_pointer = "mystring"; 
function(char *); 
function(some_pointer); 

In questo modo non è possibile trattare altri tipi di variabili.

4

È possibile creare un composto letterale:

function ((float[2]){2.0, 4.0}); 

Anche se, io non sono sicuro perché si vuole passare attraverso la briga. Questo non è permesso dall'ISO.

Generalmente, scorciatoie come questa dovrebbero essere evitate a favore della leggibilità in tutti i casi; la pigrizia non è una buona abitudine per esplorare (parere personale, ovviamente)

+0

Sono d'accordo sulla leggibilità, e in pratica questa particolare funzione sarà passata a un indirizzo di memoria e sarà felice. Tuttavia, durante i test spesso desidero semplicemente inserire alcuni valori casuali. Il tuo frammento fa il trucco, nel bene o nel male :) Grazie! – sinoth

+2

questo è valido in c99, ma nient'altro standard wise ... –

0

Purtroppo, funziona solo con array di caratteri:

void func2(char arg[]) { 
} 

int main() 
{ 
    func2("hello"); 
    return 0; 
} 
17

Questo è segnato sia in C e C++, in modo che ti capita radicalmente risposte diverse.

Se vi aspettate quattro parametri, si può fare questo:

void foo(float f[]) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2, 3, 4}; 
    foo(f); 
} 

ma che è piuttosto pericoloso, come si potrebbe fare questo per caso:

void foo(float f[]) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2}; // uh-oh 
    foo(f); 
} 

Di solito è meglio lasciare loro come parametri individuali. Dal momento che non si dovrebbe utilizzare le matrici prime in ogni caso, si può fare questo:

#include <cassert> 
#include <vector> 

void foo(std::vector<float> f) 
{ 
    assert(f.size() == 4); 

    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    float f[] = {1, 2, 3, 4}; 
    foo(std::vector<float>(f, f + 4)); // be explicit about size 

    // assert says you cannot do this: 
    foo(std::vector<float>(f, f + 2)); 
} 

un miglioramento, ma non molto di uno.Si potrebbe utilizzare boost::array, ma invece di un errore per dimensioni non corrispondenti, essi vengono inizializzati a 0:

#include <boost/array.hpp> 

void foo(boost::array<float, 4> f) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    boost::array<float, 4> f = {1, 2, 3, 4}; 
    foo(f); 

    boost::array<float, 4> f2 = {1, 2}; // same as = {1, 2, 0, 0} 
    foo(f2); 
} 

Tutto questo sarà fissato in C++ 0x, quando vengono aggiunti lista di inizializzazione costruttori:

#include <cassert> 
#include <vector> 

void foo(std::vector<float> f) 
{ 
    assert(f.size() == 4); 

    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    foo({1, 2, 3, 4}); // yay, construct vector from this 

    // assert says you cannot do this: 
    foo({1, 2}); 
} 

e probabilmente boost::array così:

#include <boost/array.hpp> 

void foo(boost::array<float, 4> f) 
{ 
    float f0 = f[0]; 
    float f1 = f[1]; 
    float f2 = f[2]; 
    float f3 = f[3]; 
} 

int main(void) 
{ 
    foo({1, 2, 3, 4}); 

    foo({1, 2}); // same as = {1, 2, 0, 0} ..? I'm not sure, 
       // I don't know if they will do the check, if possible. 
} 
0

è possibile scrivere una classe costruttore che avrebbe permesso per circa la stessa sintassi

// roughly 
template <typename C> 
class Builder { 
public: 
    template <typename T> 
    Builder(const T & _data) { C.push_back(_data); } 
    template <typename T> 
    Builder& operator()(const T & _data) { 
     C.push_back(_data); 
     return *this; 
    } 
    operator const C &() const { return data; } 
private: 
    C data; 

}; 

in questo modo, è possibile utilizzare la classe come

foo (std :: vector const & v);

foo (Builder < std :: vector> (1) (2) (3) (4));

2

È tecnicamente possibile fare riferimento all'array, ma non è ancora possibile creare l'elenco di inizializzatore anonimo.

void func(int (&bla)[4]) 
{ 
    int count = sizeof(bla)/sizeof(bla[0]); 
    // count == 4 
} 

int bla[] = {1, 2, 3, 4}; 
func(bla); 

int bla1[] = {1, 2}; 
func(bla1); // <-- fails 

Per modo C++, guarda boost::assign. Modo abbastanza pulito di riempire i contenitori STL.

0

Per aggiungere divertimento, è possibile utilizzare i modelli per renderlo variabile in lunghezza.

template<std::size_t N> 
int chars(const char(&r)[N]){ 
    std::cout << N << ": " << r << std::endl; 
    return 0; 
} 

template<std::size_t N> 
int floats(const float(&r)[N]){ 
    std::cout << N << ":"; 
    for(size_t i = 0; i < N; i++) 
     std::cout << " " << r[i]; 
    std::cout << std::endl; 
    return 0; 
} 

int main(int argc, char ** argv) { 
    chars("test"); 
    floats({1.0f, 2.0f, 3.0f, 4.0f}); 
    return 0; 
} 
Problemi correlati