如何在C中的结构中初始化const(使用malloc)

时间:2021-12-06 19:57:05

I have tried;

我努力了;

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

And this is the compiler's error:

这是编译器的错误:

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

And, also this;

而且,这也是;

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

And this is the compiler's error:

这是编译器的错误:

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

And neither got compiled. Is there any way to initialize a const variable inside a struct when allocation memory with malloc?

而且都没有汇编。有没有办法在使用malloc分配内存时初始化struct内的const变量?

4 个解决方案

#1


20  

You need to cast away the const to initialize the fields of a malloc'ed structure:

你需要抛弃const来初始化malloc结构的字段:

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

Alternately, you can create an initialized version of the struct and memcpy it:

或者,您可以创建结构的初始化版本并对其进行memcpy:

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

You can make deneme_init static and/or global if you do this a lot (so it only needs to be built once).

如果你经常这样做,你可以使deneme_init静态和/或全局(所以它只需要构建一次)。


Explanation of why this code is not undefined behaviour as suggested by some of the comments, using C11 standard references:

使用C11标准引用解释为什么此代码不是某些注释所建议的未定义行为:

  • This code does not violate 6.7.3/6 because the space returned by malloc is not "an object defined with a const-qualified type". The expression mydeneme->a is not an object, it is an expression. Although it has const-qualified type, it denotes an object which was not defined with a const-qualified type (in fact, not defined with any type at all).

    此代码不违反6.7.3 / 6,因为malloc返回的空间不是“使用const限定类型定义的对象”。表达式mydeneme-> a不是一个对象,它是一个表达式。虽然它具有const限定类型,但它表示一个未使用const限定类型定义的对象(实际上,根本没有定义任何类型)。

  • The strict aliasing rule is never violated by writing into space allocated by malloc, because the effective type (6.5/6) is updated by each write.

    写入malloc分配的空间永远不会违反严格别名规则,因为每次写入都会更新有效类型(6.5 / 6)。

(The strict aliasing rule can be violated by reading from space allocated by malloc however).

(但是,可以通过从malloc分配的空间读取来违反严格的别名规则)。

In Chris's code samples, the first one sets the effective type of the integer values to int, and the second one sets the effective type to const int, however in both cases going on to read those values through *mydeneme is correct because the strict-aliasing rule (6.5/7 bullet 2) permits reading an object through an expression which is equally or more qualified than the effective type of the object. Since the expression mydeneme->a has type const int, it can be used to read objects of effective type int and const int.

在Chris的代码示例中,第一个将整数值的有效类型设置为int,第二个将有效类型设置为const int,但是在这两种情况下继续通过* mydeneme读取这些值是正确的,因为严格 - 别名规则(6.5 / 7 bullet 2)允许通过表达式读取对象,该表达式与对象的有效类型相同或更有资格。由于表达式mydeneme-> a的类型为const int,因此它可用于读取有效类型为int和const int的对象。

#2


10  

Have you tried to do like this:

你试过这样做:

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

I have not tested but the code seems correct

我没有测试,但代码似乎是正确的

#3


2  

I disagree with Christ Dodd's answer, since I think his solution gives Undefined Behaviour according to the standards, as others said.

我不同意基督多德的回答,因为我认为他的解决方案根据标准给出了未定义的行为,正如其他人所说的那样。

To "work-around" the const qualifier in a way that does not invoke undefined behaviour, I propose the following solution:

为了以不调用未定义行为的方式“解决”const限定符,我提出以下解决方案:

  1. Define a void* variable initialized with a malloc() call.
  2. 定义使用malloc()调用初始化的void *变量。
  3. Define and object of the desired type, in this case struct deneme and initialize it in some way that const qualifier does not complain (that is, in the declaration-line itself).
  4. 定义所需类型的对象,在本例中为struct deneme,并以某种方式初始化const限定符不会抱怨(即,在声明行本身中)。
  5. Use memcpy() to copy the bits of the struct deneme object to the void* object.
  6. 使用memcpy()将struct deneme对象的位复制到void *对象。
  7. Declare a pointer to struct deneme object and initialize it to the (void*) variable, previously cast to (struct deneme *).
  8. 声明一个指向struct deneme对象的指针,并将其初始化为之前转换为(struct deneme *)的(void *)变量。

So, my code would be:

所以,我的代码是:

#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


1  

Interesting I found this C99 way is working in clang but not in gcc

有趣的是我发现这种C99方式在clang中工作但在gcc中没有

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

#1


20  

You need to cast away the const to initialize the fields of a malloc'ed structure:

你需要抛弃const来初始化malloc结构的字段:

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

Alternately, you can create an initialized version of the struct and memcpy it:

或者,您可以创建结构的初始化版本并对其进行memcpy:

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

You can make deneme_init static and/or global if you do this a lot (so it only needs to be built once).

如果你经常这样做,你可以使deneme_init静态和/或全局(所以它只需要构建一次)。


Explanation of why this code is not undefined behaviour as suggested by some of the comments, using C11 standard references:

使用C11标准引用解释为什么此代码不是某些注释所建议的未定义行为:

  • This code does not violate 6.7.3/6 because the space returned by malloc is not "an object defined with a const-qualified type". The expression mydeneme->a is not an object, it is an expression. Although it has const-qualified type, it denotes an object which was not defined with a const-qualified type (in fact, not defined with any type at all).

    此代码不违反6.7.3 / 6,因为malloc返回的空间不是“使用const限定类型定义的对象”。表达式mydeneme-> a不是一个对象,它是一个表达式。虽然它具有const限定类型,但它表示一个未使用const限定类型定义的对象(实际上,根本没有定义任何类型)。

  • The strict aliasing rule is never violated by writing into space allocated by malloc, because the effective type (6.5/6) is updated by each write.

    写入malloc分配的空间永远不会违反严格别名规则,因为每次写入都会更新有效类型(6.5 / 6)。

(The strict aliasing rule can be violated by reading from space allocated by malloc however).

(但是,可以通过从malloc分配的空间读取来违反严格的别名规则)。

In Chris's code samples, the first one sets the effective type of the integer values to int, and the second one sets the effective type to const int, however in both cases going on to read those values through *mydeneme is correct because the strict-aliasing rule (6.5/7 bullet 2) permits reading an object through an expression which is equally or more qualified than the effective type of the object. Since the expression mydeneme->a has type const int, it can be used to read objects of effective type int and const int.

在Chris的代码示例中,第一个将整数值的有效类型设置为int,第二个将有效类型设置为const int,但是在这两种情况下继续通过* mydeneme读取这些值是正确的,因为严格 - 别名规则(6.5 / 7 bullet 2)允许通过表达式读取对象,该表达式与对象的有效类型相同或更有资格。由于表达式mydeneme-> a的类型为const int,因此它可用于读取有效类型为int和const int的对象。

#2


10  

Have you tried to do like this:

你试过这样做:

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

I have not tested but the code seems correct

我没有测试,但代码似乎是正确的

#3


2  

I disagree with Christ Dodd's answer, since I think his solution gives Undefined Behaviour according to the standards, as others said.

我不同意基督多德的回答,因为我认为他的解决方案根据标准给出了未定义的行为,正如其他人所说的那样。

To "work-around" the const qualifier in a way that does not invoke undefined behaviour, I propose the following solution:

为了以不调用未定义行为的方式“解决”const限定符,我提出以下解决方案:

  1. Define a void* variable initialized with a malloc() call.
  2. 定义使用malloc()调用初始化的void *变量。
  3. Define and object of the desired type, in this case struct deneme and initialize it in some way that const qualifier does not complain (that is, in the declaration-line itself).
  4. 定义所需类型的对象,在本例中为struct deneme,并以某种方式初始化const限定符不会抱怨(即,在声明行本身中)。
  5. Use memcpy() to copy the bits of the struct deneme object to the void* object.
  6. 使用memcpy()将struct deneme对象的位复制到void *对象。
  7. Declare a pointer to struct deneme object and initialize it to the (void*) variable, previously cast to (struct deneme *).
  8. 声明一个指向struct deneme对象的指针,并将其初始化为之前转换为(struct deneme *)的(void *)变量。

So, my code would be:

所以,我的代码是:

#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


1  

Interesting I found this C99 way is working in clang but not in gcc

有趣的是我发现这种C99方式在clang中工作但在gcc中没有

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