Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中的结构中初始化常量(使用malloc)_C_Struct_Initialization_Malloc_Constants - Fatal编程技术网

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

如何在C中的结构中初始化常量(使用malloc),c,struct,initialization,malloc,constants,C,Struct,Initialization,Malloc,Constants,我试过了 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:

我试过了

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
gereksiz.c:10:5: error: assignment of read-only member 'a'
gereksiz.c:11:5: error: assignment of read-only member 'b'
还有这个,

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:3:17: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token
gereksiz.c:10:5: error: assignment of read-only member 'a'
gereksiz.c:11:5: error: assignment of read-only member 'b'

两个都没有被编译。在使用malloc分配内存时,有没有办法初始化结构内部的常量变量?

您需要丢弃常量来初始化malloc结构的字段:

struct deneme *mydeneme = malloc(sizeof(struct deneme));
*(int *)&mydeneme->a = 15;
*(int *)&mydeneme->b = 20;
或者,您可以创建结构的初始化版本,并使用它进行memcpy:

struct deneme deneme_init = { 15, 20 };
struct deneme *mydeneme = malloc(sizeof(struct deneme));
memcpy(mydeneme, &deneme_init, sizeof(struct deneme));
如果您经常这样做,您可以使
deneme\u init
静态和/或全局(因此只需要构建一次)


使用C11标准参考资料,解释为什么该代码不是某些注释所建议的未定义行为:

  • 此代码不违反6.7.3/6,因为
    malloc
    返回的空格不是“定义了常量限定类型的对象”。表达式
    mydeneme->a
    不是一个对象,它是一个表达式。尽管它有
    const
    -qualified类型,但它表示一个没有用const限定类型定义的对象(实际上,根本没有用任何类型定义)

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

(但是,从
malloc
分配的空间读取数据可能会违反严格的别名规则)


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

的对象。您是否尝试过这样做:

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

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

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

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

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

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

  • 定义一个用
    malloc()调用初始化的
    void*
    变量
  • 定义所需类型的对象,在本例中为
    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;
    }
    
    #包括
    #包括
    #包括
    致密结构{
    常数INTA;
    常数int b;
    };
    结构deneme*deneme_init(结构deneme数据){
    void*x=malloc(sizeof(struct deneme));
    memcpy(x,&data,sizeof(struct deneme));
    返回(struct deneme*)x;
    }
    内部主(空){
    结构deneme*obj=deneme_init((结构deneme){15,20,});
    printf(“obj->a:%d,obj->b:%d.\n”,obj->a,obj->b);
    返回0;
    }
    
    为了扩展@Chris Dodd的回答,我已经阅读了该标准的“语言律师”详细信息,似乎该代码定义明确:

    struct deneme deneme_init = { 15, 20 };
    struct deneme *mydeneme = malloc(sizeof(struct deneme));
    memcpy(mydeneme, &deneme_init, sizeof(struct deneme));
    
    或者,要动态创建常量限定的完整结构对象,请执行以下操作:

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

    理由:

    在深入研究这个问题时,首先需要确定的是,所谓的左值是否有一个类型,如果是,那么该类型是否带有限定符。这在C11 6.3.2.1/1中定义:

    左值是一个表达式(对象类型不是void),它可能 指定一个对象;如果左值在求值时未指定对象,则行为未定义。当一个对象被称为具有特定类型时,该类型由用于指定该对象的左值指定。可修改左值是一个左值,它不具有数组类型、不完整类型、不具有constqualified类型,并且如果它是结构或联合,则不具有任何具有constqualified类型的成员(递归地包括所有包含的聚合或联合的任何成员或元素)

    显然,左值不仅有类型,还有限定符。如果它是const限定的,或者如果它是具有const限定成员的结构,则它不是可修改的左值

    继续讨论“严格别名”和有效类型的规则,C11 6.5/7:

    访问其存储值的对象的有效类型是对象的声明类型(如果有)。87)如果通过 如果左值的类型不是字符类型,则左值的类型将成为 该访问和不修改的后续访问的有效对象类型 存储的值。如果使用将值复制到没有声明类型的对象中
    memcpy
    memmove
    ,或作为字符类型数组复制,然后是有效类型 对于该访问和不修改 值是从中复制值的对象的有效类型(如果有)。对于 对没有声明类型的对象的所有其他访问,对象的有效类型为 只是用于访问的左值的类型

  • 分配的对象没有声明的类型
  • 这意味着分配的c