Подтвердить что ты не робот

Как инициализировать const в структуре в C (с помощью 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;
}

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

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?

4b9b3361

Ответ 1

Вам нужно отбросить const, чтобы инициализировать поля структуры malloc'ed:

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

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

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

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


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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

Я не согласен с ответом Christ Dodd, так как я думаю, что его решение дает Undefined Поведение в соответствии со стандартами, как говорили другие.

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

  • Определите переменную void*, инициализированную вызовом malloc().
  • Определить и объект желаемого типа, в данном случае struct deneme, и инициализировать его каким-либо образом, чтобы const квалификатор не жаловался (то есть в самой строке объявления).
  • Используйте memcpy() для копирования битов объекта struct deneme в объект void*.
  • Объявите указатель на объект 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;
}

Ответ 4

Интересно, что я нашел, что этот способ C99 работает в clang, но не в gcc

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