È il signedness di char un problema di interfaccia?
-
25-09-2019 - |
Domanda
Supponiamo che io abbia una funzione
void foo(char *)
che, internamente, deve trattare suo ingresso come un blocco di byte NUL-terminati (per esempio, è una funzione hash sulle stringhe). Potrei lanciare l'argomento per unsigned char*
nella funzione. Potrei anche cambiare la dichiarazione di
void foo(unsigned char *)
Ora, dato che char
, signed char
e unsigned char
sono tre tipi diversi , sarebbe questo costituirebbe un cambiamento di interfaccia, sotto qualsiasi ragionevole definizione del termine "interfaccia" in C?
(Questa domanda ha lo scopo di risolvere una sollevata dal un'altra domanda. ho le mie opinioni, ma non accetterà una risposta fino a quando si arriva come un "vincitore" dai voti degli altri.)
Soluzione
Secondo la norma ISO / IEC 9899: TC3,
- chiamare una funzione tramite un'espressione di tipo incompatibile è un comportamento indefinito (6.5.2.2 § 9)
- tipi di funzione compatibile deve avere tipi di parametri compatibili (6.7.5.3 §15)
- tipi di puntatore compatibili deve puntare a tipi compatibili (6.7.5.1 §2)
-
char
,signed char
eunsigned char
sono diversi tipi di base (6.2.5 § 14) e quindi incompatibile (6.2.7 §1), che è anche esplicitamente menzionato nella nota 35 a pagina 35
Quindi sì, questo è chiaramente un cambiamento per l'interfaccia di programmazione.
Tuttavia, come char *
, signed char *
e unsigned char *
avranno rappresentazioni identici e requisiti di allineamento in qualsiasi implementazione sano del linguaggio C, l'interfaccia binaria rimarrà invariata.
Altri suggerimenti
Sì, lo è. Il codice client che in precedenza compilato non sarà più di compilazione (o comunque è in grado di generare nuove avvertenze), quindi questo è un cambiamento di rottura.
I scegliere "C - nessuno dei precedenti."
Anche se non è una risposta diretta alla domanda che in realtà ha chiesto, la soluzione giusta per la situazione sembra abbastanza semplice e ovvio per me:. Non si dovrebbe davvero utilizzare una di queste
Almeno IMO, si dispone di una buona ragione per fare altrimenti, la funzione dovrebbe accettare un void *
o (preferibilmente) void const *
. Quello che stai cercando è fondamentalmente un puntatore opaco, e questo è esattamente ciò che void *
fornisce. L'utente non ha bisogno di sapere nulla riguardo la struttura interna della vostra implementazione, e dal momento che qualsiasi altro tipo di puntatore convertirà al void *
implicitamente, è una delle poche possibilità che non si rompe qualsiasi codice esistente sia.
Esiste un char * implicitamente convertire in un unsigned char *?
- Sì - non si è rotto l'interfaccia
- No - hai trapelare implementazione
i dettagli.
No, non è. Qualsiasi modifica al codice del client è banale (soprattutto se è solo per evitare un avvertimento), e, in pratica, in praticamente qualsiasi applicazione C vi accorgerete che non hanno nemmeno bisogno di una ri-compilazione perché puntatori a char*
e unsigned char*
saranno passati esattamente allo stesso modo nella convenzione di chiamata.