Espansione del mio commento.
Ecco la lingua dello standard C online :
6.2.5 Types
...
19 The void
type comprises an empty set of values; it is an incomplete object type that
cannot be completed.
...
6.3.2.2 void
1 The (nonexistent) value of a void expression (an expression that has type void
) shall not
be used in any way, and implicit or explicit conversions (except to void
) shall not be
applied to such an expression. If an expression of any other type is evaluated as a void
expression, its value or designator is discarded. (A void expression is evaluated for its
side effects.)
...
6.5.3.4 The sizeof
and _Alignof
operators
...
1 The sizeof
operator shall not be applied to an expression that has function type or an
incomplete type, to the parenthesized name of such a type, or to an expression that
designates a bit-field member. The _Alignof
operator shall not be applied to a
function type or an incomplete type.
Quindi, in sostanza, void
implica il valore no e la dimensione no (che non è uguale alla dimensione 0
). Non puoi avere oggetti di tipo void
. Quindi, la piattaforma non ha alcun ruolo qui.
Ora, void *
potrebbe essere un problema diverso: la dimensione e la rappresentazione di un void *
possono variare tra le implementazioni e in passato ho typedef
d void *
per scopi di astrazione.
Si noti che il dereferenziazione a void *
ti lascia con un'espressione void
, che come detto sopra non ha valore né dimensione; questo è il motivo per cui non puoi eseguire l'aritmetica del puntatore su void *
e perché devi convertirlo in un tipo di puntatore diverso prima di tentare di dereferenziarlo.
Ora che ci penso, è un motivo tecnico per cui dovresti creare un void
typedef - se hai bisogno di supportare sia un 1 antico Implementazione di K & R e implementazione post-C89. Il tipo di dati void
non è stato introdotto fino allo standard del 1989; prima di allora, dovresti digitare una funzione per restituire int
(o fare affidamento sulla digitazione implicita) e ignorare il valore restituito:
foo() /* implicit int type */
{
/* do something interesting */
return 0;
}
bar() /* implicit int type */
{
...
foo(); /* return value is ignored */
return 0;
}
Quindi, supponiamo che tu voglia supportare quel codice su entrambe le piattaforme K & R e ANSI e vuoi essere buono e utilizzare la parola chiave void
dove è disponibile, quindi il tuo codice ANSI viene letto come
void foo( void ) /* takes no parameters, returns no values */
{
/* do something interesting */
}
void bar( void )
{
...
foo();
...
}
Tranne che questo codice non verrà compilato sull'implementazione di K & R, poiché non riconosce la parola chiave void
. Ancora peggio, void
ha più significati nel codice sopra; indica che la funzione non restituisce un valore, e che non richiede parametri. Non possiamo semplicemente fare typedef int void
, perché ciò spezzerebbe la dichiarazione dei parametri di funzione. Abbiamo anche bisogno del return 0
nel codice K & R, poiché una funzione int
deve restituire un valore int
.
Quindi, dovremmo fare qualcosa di simile:
#if !defined( __STDC__ ) || !defined( __STDC_VERSION__) /* Assume K&R implementation */
typedef int XYZ_void;
#define void
#define XYZ_void_return return 0
#else
typedef void XYZ_void;
#define XYZ_void_return
#endif
/* K&R equivalent ANSI equivalent */
XYZ_void foo( void ) /* int foo( ) void foo( void ) */
{ /* { { */
... /* ... ... */
XYZ_void_return; /* return 0; */
} /* } } */
/* */
XYZ_void bar( void ) /* int bar( ) void bar( void ) */
{ /* { { */
... /* ... ... */
foo(); /* foo(); foo(); */
XYZ_void_return; /* return 0; */
} /* } } */
Ho mostrato come viene elaborato il codice per entrambe le implementazioni K & R e ANSI. Ancora una volta, questo è il caso di utilizzo solo a cui riesco a pensare per creare un typedef per void
.
- Almeno 27 anni.