2014-04-24 6 views
6

Sono rimasto sorpreso quando gcc -Wall ha compilato questo messaggio senza preavviso. È davvero C legittimo? Quali sono i rischi di scrivere codice come questo?Allocazione della memoria con un puntatore non definito

#include <stdio.h> 
#include <stdlib.h> 

typedef struct { 
    int a; 
    int b; 
} MyStruct; 

int main(void) { 
    MyStruct *s = malloc(sizeof(*s)); // as opposed to malloc(sizeof(MyStruct)) 
    s->a = 5; 
    printf("%d\n", s->a); 
} 
+0

Si consiglia di eseguire questa operazione per eseguire il cast esplicito. http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – AntonH

+0

Sì, è valido e consigliato. –

+0

@AntonH non si tratta di trasmettere il risultato – SomeWittyUsername

risposta

2

sizeof viene valutato in fase di compilazione. In questo contesto, *s si risolve nel tipo di *s, non si trova il riferimento del puntatore.

Questo è il modo canonico di utilizzare sizeof. Se è stato utilizzato sizeof(int) si lascia un'apertura per un errore qualora il cambiamento di tipo (in questo caso, probabilmente improbabile, ma comunque.)

+0

Si noti che: 'funzione void (const char * n) {breve a [atoi (n)]; size_t s = sizeof (a)/sizeof (a [0]); ... codice usando a e s ...} ', il valore di' sizeof (a) 'è un calcolo in fase di esecuzione perché' a' è una matrice di lunghezza variabile VLA. (Si noti che 'sizeof (a [0])' è ancora un calcolo in fase di compilazione, però.) Non faccio affermazioni per la qualità del codice eccetto per questo stretto scopo pedagogico (è terribile). –

+0

@JonathanLeffler: È vero, le VLA sono l'eccezione. –

5

Non solo è legittimo, è addirittura preferibile all'alternativa. In questo modo si consente al compilatore di dedurre il tipo effettivo invece di farlo manualmente.

1

scrittura

MyStruct *s = malloc(sizeof(*s)); 

ha esattamente lo stesso effetto di

MyStruct *s = malloc(sizeof(MyStruct)); 

eccetto che ora scrivi solo MyStruct una volta. Cioè, l'oggetto che stai allocando ha la sua fonte tipo determinata automaticamente, che riduce le possibilità di errori.

Ad esempio, è successo a me: si inizia con un MyStruct. Quindi decidi di aver bisogno di un diverso MyStruct per diversi scopi. Quindi finisci con due strutture diverse, MyStruct e AnotherStruct.

Poi si refactoring del codice e modificare alcune variabili MyStruct-AnotherStruct, e finisce con

AnotherStruct *s = malloc(sizeof(MyStruct)); 

che potrebbe effettivamente funzionare in diverse circostanze, o per un lungo periodo di tempo, fino a fare un altro po 'e , a quel punto, cambiamento completamente indipendente in entrambe le strutture. A che punti il ​​tuo codice va kaboom.

E.g.

typedef struct { 
     int a; 
     int b; 
} StructA; 

typedef struct { 
     int a; 
     int b; 
     int c; 
} StructB; 

int main() { 
     // No problem here except wasted space 
     StructA *s = malloc(sizeof(StructB)); 

     // t->c dwells in undefined country 
     StructB *t = malloc(sizeof(StructA)); 
} 
Problemi correlati