2012-03-13 33 views
19

Lo he intentado;Cómo inicializar const en una estructura en C (con malloc)

void *malloc(unsigned int); 
struct deneme { 
    const int a = 15; 
    const int b = 16; 
}; 

int main(int argc, const char *argv[]) 
{ 
    struct deneme *mydeneme = malloc(sizeof(struct deneme)); 
    return 0; 
} 

Y este es el error del compilador:

gereksiz.c:3:17: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token 

Y, también esto;

void *malloc(unsigned int); 
struct deneme { 
    const int a; 
    const int b; 
}; 

int main(int argc, const char *argv[]) 
{ 
    struct deneme *mydeneme = malloc(sizeof(struct deneme)); 
    mydeneme->a = 15; 
    mydeneme->b = 20; 
    return 0; 
} 

Y este es el error del compilador:

gereksiz.c:10:5: error: assignment of read-only member 'a' 
gereksiz.c:11:5: error: assignment of read-only member 'b' 

Y tampoco obtuve compilado. ¿Hay alguna manera de inicializar una variable const dentro de una estructura cuando se asigna la memoria con malloc?

+0

@KerrekSB por supuesto. – yasar

+0

@KerrekSB ver mis ediciones. – yasar

+0

Tiene que descartar constness: '* (int *) (& mydeneme-> a) = 15;' –

Respuesta

18

Necesitas desecharon la const para inicializar los campos de una estructura malloc'ed:

struct deneme *mydeneme = malloc(sizeof(struct deneme)); 
*(int *)&mydeneme->a = 15; 
*(int *)&mydeneme->b = 20; 

Como alternativa, puede crear una versión inicializado de la estructura y que memcpy:

struct deneme deneme_init = { 15, 20 }; 
struct deneme *mydeneme = malloc(sizeof(struct deneme)); 
memcpy(mydeneme, &deneme_init, sizeof(struct deneme)); 

Puede hacer que deneme_init sea estático y/o global si hace esto mucho (por lo que solo debe crearse una vez).


Explicación de por qué este código no es un comportamiento indefinido según lo sugerido por algunos de los comentarios, usando referencias estándar C11:

  • Este código no viola 6.7.3/6 porque el espacio devuelto por malloc no es "un objeto definido con un tipo const-qualified". La expresión mydeneme->a no es un objeto, es una expresión. Aunque tiene const -tipo calificado, denota un objeto que no se definió con un tipo const-calificado (de hecho, no se define con ningún tipo).

  • La regla de alias estricto no se viola escribiendo en el espacio asignado por malloc, debido a que el tipo efectivo (6,5/6) se actualiza por cada escritura.

(aliasing La regla estricta pueden ser violados por la lectura desde el espacio asignado por malloc sin embargo).

En ejemplos de código de Chris, el primero establece el tipo efectivo de los valores enteros a int, y la segunda establece el tipo eficaz para const int, sin embargo en ambos casos de pasar a leer esos valores a través de *mydeneme es correcto porque el La regla de alias estrictos (6.5/7 punto 2) permite leer un objeto a través de una expresión igual o más calificada que el tipo efectivo del objeto. Como la expresión mydeneme->a tiene el tipo const int, se puede utilizar para leer objetos del tipo efectivo int y const int.

+7

¿No es el comportamiento indefinido de acceso directo? –

+8

* Muy * indefinido. –

+8

No - const cast está bien definido si la memoria en cuestión no es const (como la que viene de malloc). No está definido si intentas modificar un objeto const a través del molde. –

10

Ha intentado hacer así:

int main(int argc, const char *argv[]) 
{ 
    struct deneme mydeneme = { 15, 20 }; 
    struct deneme *pmydeneme = malloc(sizeof(struct deneme)); 
    memcpy(pmydeneme, &mydeneme , sizeof(mydeneme)); 
    return 0; 
} 

no he probado, pero el código parece correcto

1

interesante que encontré esta manera C99 está trabajando en el sonido metálico, pero no en gcc

int main(int argc, const char *argv[]) 
{ 
    struct deneme *pmydeneme = malloc(sizeof(struct deneme)); 
    *pmydeneme = (struct deneme) {15, 20}; 
    return 0; 
} 
+0

¡Bienvenido a Stack Overflow! Esto quizás debería haber sido un comentario, pero si tiene una nueva pregunta, por favor, haga clic en el botón [Ask Question] (http://stackoverflow.com/questions/ask); es posible que desee incluir un enlace a este para el contexto. –

+2

@NathanTuggy me parece una respuesta –

+0

@MattMcNabb: Tal vez; la mención "does not work in gcc" me echó. –

2

No estoy de acuerdo con La respuesta de Christ Dodd, ya que creo que su solución da Comportamiento indefinido según los estándares, como otros dijeron.

Para "trabajo en torno a" la const calificador de una manera que no invoque un comportamiento indefinido, propongo la siguiente solución:

  1. definir una variable void* inicializado con una llamada malloc().
  2. Defina y objeto del tipo deseado, en este caso struct deneme e inícielo de alguna manera que el calificador const no se queje (es decir, en la línea de declaración).
  3. Utilice memcpy() para copiar los bits del objeto struct deneme al objeto void*.
  4. Declara un puntero al objeto struct deneme y lo inicializa a la variable (void*), previamente emitida como (struct deneme *).

Por lo tanto, mi código sería:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
struct deneme { 
    const int a; 
    const int b; 
}; 
struct deneme* deneme_init(struct deneme data) { 
    void *x = malloc(sizeof(struct deneme)); 
    memcpy(x, &data, sizeof(struct deneme)); 
    return (struct deneme*) x; 
} 
int main(void) { 
    struct deneme *obj = deneme_init((struct deneme) { 15, 20, }); 
    printf("obj->a: %d, obj->b: %d.\n", obj->a, obj->b); 
    return 0; 
} 
Cuestiones relacionadas