2010-02-08 16 views
33

Vorrei allocare una struttura sull'heap, inizializzarla e restituire un puntatore ad esso da una funzione. Mi chiedo se c'è un modo per me per inizializzare i membri const di una struttura in questo scenario:Come inizializzare i membri const delle strutture nell'heap

#include <stdlib.h> 

typedef struct { 
    const int x; 
    const int y; 
} ImmutablePoint; 

ImmutablePoint * make_immutable_point(int x, int y) 
{ 
    ImmutablePoint *p = (ImmutablePoint *)malloc(sizeof(ImmutablePoint)); 
    if (p == NULL) abort(); 
    // How to initialize members x and y? 
    return p; 
} 

Devo concludere da questo che è impossibile per allocare e inizializzare una struct sul mucchio che contiene i membri const ?

risposta

48

Come così:

ImmutablePoint *make_immutable_point(int x, int y) 
{ 
    ImmutablePoint init = { .x = x, .y = y }; 
    ImmutablePoint *p = malloc(sizeof *p); 

    if (p == NULL) abort(); 
    memcpy(p, &init, sizeof *p); 

    return p; 
} 

(Si noti che a differenza di C++, non c'è bisogno di lanciare il valore di ritorno di malloc in C, ed è spesso considerato di cattivo gusto perché può nascondere altri errori).

+6

Si noti che l'uso di .x e .y nell'inizializzazione di init è C99, ovviamente è possibile utilizzare voci unamed se il compilatore non lo supporta. – Trent

+0

Brillante, caf - grazie! – user268344

+4

+1 Per il chiarimento su 'malloc' tra C e C++. –

10

Se questo è C e non C++, non vedo altra soluzione che sovvertire il sistema di tipi.

ImmutablePoint * make_immutable_point(int x, int y) 
{ 
    ImmutablePoint *p = malloc(sizeof(ImmutablePoint)); 
    if (p == NULL) abort(); 

    // this 
    ImmutablePoint temp = {x, y}; 
    memcpy(p, &temp, sizeof(temp)); 

    // or this 
    *(int*)&p->x = x; 
    *(int*)&p->y = y; 

    return p; 
} 
+1

Se questo è C, la trasmissione del valore di ritorno di 'malloc' non è necessaria e ridondante. – dreamlax

+1

@dreamlax: buona cattura. Mi manca molto di C

2

Se ti ostini a mantenere il const nella struttura, che si sta per fare un po 'di fusione per aggirare questo:

int *cheat_x = (int *)&p->x; 
*cheat_x = 3; 
+2

Non invoca un comportamento indefinito? – dreamlax

+2

Se hai allocato la memoria, penso che vada bene. – NateS

0

mi piace caf's approach, ma questo si è verificato anche a me

+0

Siamo spiacenti, non vedo il const qui. Puoi spiegare per favore? – kevinarpe

+1

@KCArpe: alloco e assegno una 'struct' che è identica nella struttura a' ImmutablePoint' ma è mutabile, quindi lancia il puntatore nell'istruzione return in modo che la versione mutabile non sia mai visibile all'utente.È un abuso abusivo del casting per "interrompere" il sistema di tipi. Lo svantaggio della soluzione di questo relativo caf è che non è [DRY] (http://en.wikipedia.org/wiki/Don%27t%5Frepeat%5Fyourself): se qualcuno modifica "ImmutablePoint", devo modificare "unconstpoint". anche. – dmckee

+3

viola l'aliasing del puntatore. –

Problemi correlati