【问题标题】:C++: how to assign static array to a pointer inside a structC ++:如何将静态数组分配给结构内的指针
【发布时间】:2018-04-15 00:44:08
【问题描述】:

我有需要编译为 C++ 的 C 代码,并且需要对其进行最低限度的更改。

在 C 中,以下工作

typedef struct _type_t
{
    int a;
    int b;
    int c[];
}type_t;

type_t var = {1,2,{1,2,3}};

但在 C++11 中,它给出了错误

错误:int [0] 的初始化程序太多

但我不能给type_t.c 一个恒定大小,因为它需要适用于任何大小的数组。

所以我需要将结构更改为

typedef struct _type_t
    {
        int a;
        int b;
        int *c;
    }type_t;

但是我需要改变

type_t var = {1,2,{1,2,3}};

因为当前代码给出了错误,所以换成别的东西

错误:int* 类型的标量初始值设定项大括号

将第三个元素转换为(int[]) 会出错

错误:获取临时数组的地址

这是来自micropython, parse.c

#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };

如何初始化数组并将其分配给 type_t.c

【问题讨论】:

  • gcc 使用您的 C 代码发出警告:“警告:灵活数组成员 [-Wpedantic] 的初始化”( gcc -Wall -pedantic -std=c11 )
  • 您需要知道c 的大小才能执行此操作。例如,如果 int c[];int c[3];,它会起作用
  • @Adrian 为什么会这样? C 不是 C++ 不是 C。
  • @Adrian - 不,它在 C 中不起作用。它在您以前提供扩展的编译器下工作。 C 语言规范明确禁止它。
  • @StoryTeller 我猜你是对的:it's not allowed by C standard 但它适用于 gcc。

标签: c++ arrays c++11 struct


【解决方案1】:

使用std::vectoraggregate initialization

struct type_t
{
    int a;
    int b;
    std::vector<int> c;
};

int main() {
    type_t var = { 1, 2, { 1, 2, 3 } };
}

【讨论】:

  • 这不是一个选项。我需要尽可能少地修改它,即不引入 stl 的使用。
  • 当然可以。这是首选。
  • 那我得修改所有使用type_t的代码
  • @Adrian std::vector 已重载 operator[],因此您仍然可以访问存储在 std::vector 中的元素,就像访问数组元素一样。
  • @Adrian 那么你需要接受 C++ 不是 C 并且有些事情你必须做不同于你在 C 中所做的事情。
【解决方案2】:

为了做到这一点,你需要使你的数组​​真正静态:

typedef struct _type_t
{
    int   a;
    int   b;
    int * c;
}type_t;

int items[3] = {1,2,3};
type_t var = {1,2, static_cast< int * >(items)};

【讨论】:

  • 既然这样可行,为什么不能在{} 中声明一个数组?
  • @Adrian - 因为 C++ 不允许。你不能强迫语言变成它不是的东西。
  • 这个解决方案比投票率最高的解决方案更符合将现有 C 代码转换为 C++ 的任务。
  • @StoryTeller 这使对象的内存占用与以前相同。有可能在某个地方潜伏着对 _type_t.c 类型转换为 int* 的访问。或者假设特定大小的 _type_t 的 memcpy。或 addind std::vector 的复杂性。我之前已经转换过遗留代码库,通常情况下,更改越少越好。即使你最终得到了这样的骇人听闻的东西。
  • @Jeffrey - 老实说,在我看来,正确的转换是继续将其编译为带有扩展的 C。只需将其紧紧包裹在符合标准的危险品代码套装中即可。
【解决方案3】:

C++ 不允许这种语句表达式。您可以使用轻量级std::initialiser_list 来实现目标

#include <initializer_list>
typedef struct _type_t
{
    int a;
    int b;
    std::initializer_list<int> c;
}type_t;

 type_t var = {1,2,{1,2,3,4}};

【讨论】:

  • initializer_list 不提供operator[]。 OP 将无法将其用作替代品。
  • Story Teller :是的,它不提供下标,并且必须使用迭代器来遍历它。但与矢量相比,它非常轻巧,并且可以根据自己的要求选择使用它
  • 恐怕它太轻了。一方面,需要考虑对象生命周期的考虑。成员c 是否会延长从{1, 2, 3, 4} 创建的临时数组的寿命?我不认为它会。由于 OP 还希望减少替代品,因此这里没有帮助。
  • 它也不够轻量,不能保证这样的type_t仍然是POD;所以即使它是正确的,你也不会比 std::vector 获得什么
  • 我猜功能/程序的要求应该决定选择什么。它是一种选择,可能不是每种情况下的最佳选择,但在内存和复杂性方面它绝对比向量更好,因为不需要动态增长它(根据上面的代码)
【解决方案4】:

另一种选择可能是

    ...
    int * c;
}type_t;

type_t var = {1,2, []{ static int x[] = {1,2,3}; return x; }() };

PS:是的,我知道这很疯狂,但它更尊重 OP 要求(它可以合并到给定的 dropin 替换宏中)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 2019-04-23
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多