Как инициализировать const в структуре в C (с помощью malloc) - PullRequest
20 голосов
/ 14 марта 2012

Я пытался;

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

И это ошибка компилятора:

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

И, также это;

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

И этоошибка компилятора:

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

И ни один не был скомпилирован.Есть ли способ инициализировать переменную const внутри структуры при выделении памяти с помощью malloc?

Ответы [ 4 ]

24 голосов
/ 14 марта 2012

Вам нужно отбросить const для инициализации полей структуры malloc:

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

В качестве альтернативы, вы можете создать инициализированную версию структуры и запомнить ее:

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

Вы можете сделать deneme_init статическим и / или глобальным, если вы делаете это много (поэтому его нужно создать только один раз).


Объяснение того, почему этот код не является неопределенным поведением, как это предлагаетсясогласно некоторым комментариям, используя стандартные ссылки C11:

  • Этот код не нарушает 6.7.3 / 6, поскольку пространство, возвращаемое malloc, не является "определенным объектом с константным типом ".Выражение mydeneme->a это не объект, это выражение.Несмотря на то, что он имеет const -квалифицированный тип, он обозначает объект, который не был определен с помощью типа с константой (фактически, вообще не определен ни с одним типом).

  • правило строгого алиасинга никогда не нарушается записью в пространство, выделенное malloc, потому что эффективный тип (6.5 / 6) обновляется при каждой записи.

(Строгое правило алиасинга может быть нарушено чтением из пространства, выделенного на malloc.)

В примерах кода Криса первый устанавливает эффективный тип целочисленных значений равным int, а второйустанавливает эффективный тип на const int, однако в обоих случаях чтение этих значений с помощью *mydeneme является правильным, поскольку правило строгого псевдонима (п. 6,5 / 7, 2) позволяет читать объект через выражение, равное или большееуточняется, чем эффективный тип объекта.Поскольку выражение mydeneme->a имеет тип const int, его можно использовать для чтения объектов эффективного типа int и const int.

.
10 голосов
/ 14 марта 2012

Вы пытались сделать так:

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

Я не проверял, но код кажется правильным

2 голосов
/ 26 февраля 2017

Я не согласен с ответом Христа Додда , поскольку я думаю, что его решение дает Неопределенное поведение в соответствии со стандартами, как говорили другие.

Чтобы "обойти" квалификатор const способом, который не вызывает неопределенного поведения, я предлагаю следующее решение:

  1. Определение переменной void*, инициализированной с помощьюmalloc() вызов.
  2. Определите и объект нужного типа, в данном случае struct deneme и инициализируйте его некоторым образом, чтобы квалификатор const не жаловался (то есть в самой строке объявления).
  3. Используйте memcpy() для копирования битов объекта struct deneme в объект void*.
  4. Объявите указатель на объект struct deneme и инициализируйте его переменной (void*), ранее приведенной к (struct deneme *).

Итак, мой код будет:

#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;
}
1 голос
/ 18 февраля 2015

Интересно, я обнаружил, что этот способ C99 работает в Clang, но не в GCC

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