【问题标题】:c make a copy of an array of const structsc 复制一个 const 结构数组
【发布时间】:2014-11-12 04:57:14
【问题描述】:

我有一个结构数组,其中一些结构成员是常量 我想制作数组的深层副本。 该副本也将具有相同的结构成员是常量。 如何在不违反 const 指令的情况下将值初始化到新数组中。

以下是我的代码的摘录。实际程序很长,但我想我已经包含了所有相关代码。在这个例子中 keys 被声明为一个全局变量,我想从中创建新实例。我将其视为具有预设值的模板。

当我尝试在 Debian 中使用 gcc 进行编译时,出现以下错误:

main.c:216:9: error: assignment of read-only location ‘*(new_keys + (unsigned int)((unsigned int)index * 540u))’make: *** [main.o] Error 1

makefile 使用以下限定符:

CFLAGS=-c -g -std=gnu99 -D_XOPEN_SOURCE=700

有趣。即使将 Xcode 设置为 C 语言方言 GNU99[-std=gnu99]

,我也可以在 Xcode 中编译相同的代码而不会出现错误或警告

我可以通过去掉 const 关键字来使我的代码正常工作。但这些值确实应该是 const。一旦这些数组被初始化,它们就永远不会改变。我想了解如何正确执行此操作,并且我想知道为什么这在 Xcode 而不是 gcc 中有效。

头文件

typedef struct {
    char * name;
    char * alias;
    int number;
} pair_int_t;

typedef struct {
    const char * const name;
    const kind_t kind; // kind is enum type
    const pair_int_t * const enum_array; 
    bool received; 
    const char * const alias; 
} key_descriptor_t;

typedef key_descriptor_t keys_descriptor_t[_END_OF_KEYS+1];

main() 之前的 .c 程序主体

const pair_int_t command_list[] = {
    {.name = "numeric data response",        .alias = "num",         .number = RES_NUMERIC_DATA},
    {.name = "read attribute",               .alias = "readat",      .number = CMD_READ_ATTR},
    //..
}

// declare a global variable *keys* with constants assigned to it
key_descriptor_t keys[] = {
    [_COMMAND]          = {.name = "command",           .kind = ENUMERATED, .alias = "com",    .enum_array = command_list},
    [_RESPONSE]         = {.name = "response",          .kind = ENUMERATED, .alias = "res",    .enum_array = command_list},
    [_UNIT]             = {.name = "unit number",       .kind = NUMBER,     .alias = "uni",    .enum_array = NULL},
//..
}

int initialize_new_keys(keys_descriptor_t new_keys) {
    int index;
    for (index = _FIRST_KEY; index <= _END_OF_KEYS; index++){
        new_keys[index] = keys[index];      // line 216, keys is a global variable  
    }
    return index;
}

主程序

int main(int argc, const char * argv[]){
    keys_descriptor_t 2nd_set_of_keys;
    initialize_new_keys(2nd_set_of_keys);
}

【问题讨论】:

    标签: c arrays struct copy constants


    【解决方案1】:

    “2nd_set_of_keys”是一个struct,它应该是一个静态数组(也可以是一个指针并动态保留内存),“new_keys”参数也会出现同样的问题。 虽然有点奇怪,但您可以使用 memcpy() 将数据复制到 const 变量(覆盖 const 验证)。

    【讨论】:

      【解决方案2】:

      您只能在定义const 变量时对其进行初始化。使用const 成员创建一个数组,将其发送到一个函数,然后尝试分配给这些成员,这表明您最初并不是真的指const。 C 中没有“const 除了第一个赋值”的语法。

      一个合理的选择是制作一个不透明类型,将定义封装在一个单独的翻译单元中,然后纯粹通过函数接口访问所有成员。这样,即使事情可能不是const,它们仍然无法更改(除非通过故意颠覆,这至少比不首先调用const),因为没有使用它们的代码可以访问struct 的定义,因此也可以访问成员。

      编辑:针对评论中的问题,“有没有办法创建一个复杂的常量变量并将其初始化为另一个相同类型的现有常量变量的值?”,当然是 - 只需正常初始化它:

      struct mystruct {
          const int a;
          const int b;
      };
      
      static const struct mystruct m = {1, 2};
      
      int main(void) {
          struct mystruct n = m;
          return 0;
      }
      

      显然,您的struct 越复杂,它可能会变得越复杂。

      【讨论】:

      • 我认为在我的结构定义中放置const 会使结构的成员成为常量而不是整个结构本身。因此,当我分配new_keys[index] = keys[index]; 时,我以为我正在制作一个包含一些 const 成员的非常量结构的副本,并将其放置在数组的非常量成员中。我在 gcc 中遇到的错误实际上是否意味着我违反了 const 属性?错误的 540u 部分是什么?
      • 问题是当你的整体struct 被创建时你的struct 成员被创建(他们必须这样做,否则“创建struct”将没有任何意义),所以一旦你创建了struct,你就已经有了const 成员,如果你在创建时没有初始化它们,你就失去了这样做的机会。 540u 只是一个等于 540 的无符号整数,它只是 gcc 在您的数组上进行指针运算。是的,这里的问题是违反const
      • @TimothyVann 错误消息很奇怪,但错误肯定是您正在尝试写入 const 位置
      • 因此,当我进行分配 = keys[index](其计算结果为结构)时,我将键 [index] 处现有结构中的值复制到 new_keys[index] 处的另一个现有结构中当我使用keys_descriptor_t 2nd_set_of_keys; 创建数组时,它被初始化了?对吗?
      • 为什么使用 gnu99 的 Xcode 允许这样做,而 gcc 不允许这样做?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-10
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 2015-05-24
      相关资源
      最近更新 更多