Posso usare i cast in stile C quando chiami le funzioni C da C ++?

4

Ho letto entrambi su questo sito e altrove, che lo stile di programmazione raccomandato per C ++ è quello di evitare l'uso di cast in stile C, e preferiamo lo stile C ++ - static_cast , dynamic_cast , reinterpret_cast e const_cast . Le ragioni di questa raccomandazione generalmente si riducono a (1) i cast di C ++ sono più sicuri perché sono più specifici e limitati nel significato e (2) sono intenzionalmente prolissi e prolissi perché non dovrebbero essere usati spesso in un buon codice C ++. Tuttavia, questo ragionamento non ha molto senso quando si tratta di chiamare le funzioni C dal mio codice C ++.

Nei miei progetti C ++ sono spesso costretto a chiamare librerie a livello di OS che hanno solo un'interfaccia C, come la libreria di socket POSIX per le operazioni di rete. Queste funzioni C spesso si aspettano che il chiamante esegua diversi cast di puntatori, e se io tengo solo i cast di C ++, il mio codice diventa goffo e prolisso. Ad esempio, il mio codice di rete è pieno di chiamate di funzioni come questa:

std::size_t message_size;
ssize_t bytes_read = recv(fd, reinterpret_cast<char*>(&message_size), sizeof(message_size), MSG_WAITALL);

Non sto ottenendo alcuna sicurezza dall'uso di cast di C ++ (dal momento che reinterpret_cast non aggiunge realmente più controlli in fase di compilazione di un cast in stile C) e la bruttezza del codice non mi sta allertando un problema: non è possibile utilizzare le funzioni di socket senza eseguire il casting.

Alla luce della mancata corrispondenza dell'interfaccia tra C e C ++, sarebbe ragionevole usare cast in stile C quando si chiamano funzioni C che richiedono il cast? O i cast di tipo C sono sempre cattivi, e dovrei semplicemente accettare il codice in eccesso quando devo chiamare le funzioni C?

    
posta Edward 13.12.2017 - 19:29
fonte

2 risposte

7

È facile impedire che la verbosità di chiamare le funzioni C ingombra il tuo codice: avvolgili. Nel caso di recv , ad esempio, puoi semplicemente fare questo:

template <typename T>
ssize_t recv(int fd, T& data) {
  return ::recv(fd, reinterpret_cast<char*>(&data), sizeof(data), MSG_WAITALL);
}

Puoi migliorare su questo ad es. static_assert ing che T è banalmente copiabile o ha altre proprietà desiderate.

Ora, se si utilizza questa funzione al posto di C recv su tutto il codice, si ha un ingombro ridotto e una sicurezza migliorata (non si può accidentalmente mismatchare il tipo di dati e le sue dimensioni).

Allo stesso tempo, stai ancora utilizzando cast di stile C ++, che ti impedisce di lanciare casualmente la costanza.

    
risposta data 13.12.2017 - 22:00
fonte
4

Lo standard spiega come funziona il cast di stile C (N4296):

5.4/4: The conversions performed by

  • a const_cast,
  • a static_cast,
  • a static_cast followed by a const_cast,
  • a reinterpret_cast , or
  • a reinterpret_cast followed by a const_cast,

can be performed using the cast notation of explicit type conversion. (...)

Senza entrare nei dettagli, il resto del paragrafo spiega anche che il cast di C rilassa alcuni vincoli che si applicherebbero a static_cast in presenza di puntatori a classi derivate. Questo atteggiamento rilassato è uno dei motivi per cui si consiglia di non utilizzarlo in codice C ++.

Nel tuo caso, usando (char*)&message_size si otterrebbe reinterpret_cast<char*>(&message_size) da generare dal compilatore. Quindi non perdere nulla usando reinterpret_cast direttamente.

Bjarne Stroustrup offre un paio di altri motivi, perché il cast di C ++ dovrebbe essere preferito nel suo libro " The design and evolution of C ++ ":

To sum up, old-style cast:

  1. Are a problem for understanding: they provide a single notation for several weakly related operations
  2. Are error-prone: almost every type combination [i.e. source type and target type] has a legal interpretation
  3. Are hard to spot in code and hard to find with simple tools
  4. Complicate the C and C++ grammars

The new cast operators represent a classification of the old's cast functionality.

Naturalmente, nel tuo caso particolare, i punti 1, 2 e 4 non sono un problema reale. Tuttavia, l'uso del nuovo stile ti porterà il vantaggio del punto 3 e ti abituerà alla maggiore precisione che viene comunemente utilizzata nella trasmissione C ++.

D'altra parte, IMHO, non sarebbe scioccante usare ancora la sintassi C se si limita il suo uso all'esclusiva evidenza nel codice dell'interoperabilità con le librerie C.

    
risposta data 13.12.2017 - 20:29
fonte

Leggi altre domande sui tag