2010-02-08 43 views
33

Me gustaría asignar una estructura en el montón, inicializarla y devolverle un puntero desde una función. Me pregunto si hay una manera para mí para inicializar los miembros const de una estructura en este escenario:Cómo inicializar miembros const de estructuras en el montón

#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; 
} 

¿Debo deducir de esto que es imposible asignar e inicializar una estructura en el montón que contiene miembros const ?

Respuesta

48

así:

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; 
} 

(Tenga en cuenta que a diferencia de C++, no hay necesidad de emitir el valor de retorno de malloc en C, y que a menudo se considera de mala, ya que puede ocultar otros errores).

+6

Tenga en cuenta que el uso de .x y .y en la inicialización de init es C99; por supuesto, puede usar entradas unificadas si su compilador no lo admite. – Trent

+0

Brillante, caf - ¡gracias! – user268344

+4

+1 Para la aclaración sobre 'malloc' entre C y C++. –

10

Si esto es C y no C++, no veo otra solución que subvertir el sistema de tipos.

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

Si esto es C, el lanzamiento del valor de retorno de 'malloc' es innecesario y redundante. – dreamlax

+1

@dreamlax: buena captura. Realmente extraño eso sobre C

2

Si insiste en mantener la const en la estructura, que van a tener que hacer algún casting para conseguir alrededor de eso:

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

¿Eso no invoca comportamiento indefinido? – dreamlax

+2

Si asignó la memoria, creo que está bien. – NateS

0

me gusta caf's approach, pero esto ocurrió a mí también

ImmutablePoint* newImmutablePoint(int x, int y){ 
    struct unconstpoint { 
     int x; 
     int y; 
    } *p = malloc(sizeof(struct unconstpoint)); 
    if (p) { // guard against malloc failure 
     *p.x = x; 
     *p.y = y; 
    } 
    return (ImmutablePoint*)p; 
} 
+0

Lo siento, no veo la const aquí. ¿Puede usted explicar por favor? – kevinarpe

+1

@KCArpe: asigno y asigno una estructura 'struct' que es idéntica en estructura a 'ImmutablePoint' pero es mutable, luego lanzo el puntero en la declaración de devolución para que la versión mutable nunca sea visible para el usuario.Es un abuso de casting bastante estándar para "romper" el sistema de tipos. La desventaja de esta solución relativa de caf es que no es [DRY] (http://en.wikipedia.org/wiki/Don%27t%5Frepeat%5Fyourself): si alguien edita 'ImmutablePoint', necesito editar' unconstpoint' también. – dmckee

+3

esto viola el alias de puntero estricto. –

Cuestiones relacionadas