2013-05-07 7 views
9

È ben definita per passare std :: vector a API C che prevedono un array output come questo perché std :: vector è contiguo:È sicuro passare std :: string alle API in stile C? C++

std::vector<char> myArray(arraySize); 
cStyleAPI(&myArray[0], arraySize); 

È sicuro passare std :: string nello stesso modo alle API C? C'è qualche garanzia nello standard C++ 03 che std :: string è contigua e funziona allo stesso modo di std :: vector in questa situazione?

risposta

9

Se la funzione API C richiede l'accesso in sola lettura al contenuto di std::string, utilizzare la funzione membro std::string::c_str() per passare la stringa. Questo è garantito per essere una stringa terminata da null.

Se si intende utilizzare il std::string come parametro fuori, C++ 03 non garantisce che la stringa memorizzata è contiguo in memoria, ma C++ 11 fa. Con quest'ultimo è possibile modificare la stringa tramite operator[] purché sia ​​don't modify the terminating NULL character.

+0

c_str() restituisce un const char * e devo essere in grado di ricevere l'output nella stringa. Va bene farlo senza usare const_cast e c_str()? – masrtis

+0

@masrtis No, non lo è ancora, ma allora perché non usi 'char buf [BUFSIZE]'? –

+0

@masrtis Beh, praticamente sulla maggior parte delle implementazioni ragionevoli? Sì! Ma teoricamente garantito dallo standard? Sicuramente no! –

0

No, non lo è, ma generalmente perché si presume che le stringhe C siano terminate da zero, che il puntatore-a-char non è. (Se si utilizza string, è possibile utilizzare string::c_str() invece, che è 0-terminato.)

Comunque, C++ 11 richiede gli elementi di vector essere contigui in memoria.

1

Sì, ma è necessario passarli utilizzando il metodo c_str per garantire la terminazione null.

0
cStyleAPI(&myArray[0], arraySize); 

Se il cStyleAPI riceve un char * per l'input, che è quello che è per std::string::c_str().

Se riceve un carattere pre-assegnato * per l'output, quindi no. In tal caso, è necessario utilizzare uno std::vector<char> o std::array<char>.

5

Quindi, so che questo è stato già risposto, ma ho visto il tuo commento in risposta Pretorio:

E 'un driver bug OpenGL che si traduce nel valore di ritorno per la stringa lunghezza massima di essere rotto. Vedi https://forums.geforce.com/default/topic/531732/glgetactiveattrib-invalid/. glGetActiveAttrib non tenterà di scrivere sul puntatore restituito dalla chiamata nuova [] con l'allocazione della dimensione 0, ma la stringa non è nullo terminata. Quindi, più avanti nel codice, la stringa terminata non nulla è copiata in una std :: string per l'archiviazione, che risulta in un overflow del buffer di lettura . Molto confusionario anche a me, e sto solo controllando qui per vedere se std :: string renderebbe le cose più facili da seguire.

Uhm ... mi perdoni, ma se questo è il vostro problema, allora tutte queste soluzioni sembrano essere eccessivamente complicato.Se il problema si riduce al fatto che si ottiene uno 0 come dimensione del buffer che è necessario (il che significa che si finirà con una stringa che non è terminata con NULL, poiché non c'è spazio per il terminatore NULL) quindi semplicemente assicurarsi un terminatore NULL è sempre presente:

int arraySize; 

/* assume arraySize is set to the length we need */ 
... 

/* overallocate by 1 to add an explicit NULL terminator. Just in case. */ 
char *ptr = malloc(arraySize + 1); 

if(ptr != NULL) 
{ 
    /* zero out the chunk of memory we got */ 
    memset(ptr, 0, arraySize + 1); 

    /* call OpenGL function */ 
    cStyleAPI(ptr, arraySize); 

    /* behold, even if arraySize is 0 because of OpenGL, ptr is still NULL-terminated */ 
    assert(ptr[arraySize] == 0); 

    /* use it */ 
    ... 

    /* lose it */ 
    free(ptr); 
} 

Questo sembra, per me, per essere la soluzione più sana più semplice.

+0

Dovrebbe essere il più semplice, sì. Solo curioso: qualche motivo particolare per usare 'malloc' e' memset' e non 'calloc'? –

+1

Non proprio - solo abitudine. –

+0

Oppure nuovo [] ed elimina [], del resto? – Joel

Problemi correlati