我正在一个C ++项目中工作,我正在尝试创建一个拥有数组的结构,其大小将在调用方法时确定。但是,这给了我一个着名的错误“数组绑定不是一个整数常量”(使用GCC和Qt)。
我在StackOverflow和其他地方做了一些研究,但是找不到任何解决方案来解决我的特殊情况:数组的大小显然是非常量的,或者当找到数组时问题没有出现在结构内部,而不是在结构之外。
提供我用于测试的代码:
void QuantitySelectorCenterView::accepted()
{
const int numItems = modelSelectedList->rowCount();
uchar selectedItemsX[numItems];
struct PQDataRequest
{
re8k_ict_header header;
re8k_ict_physical_quantity quantity;
uchar selectedItems[numItems];
};
struct PQDataRequest2
{
re8k_ict_header header;
re8k_ict_physical_quantity quantity;
uchar selectedItems[10];
};
}
在下面的代码中,modelSelectedList的“rowCount()”值是在运行时定义的,具体取决于用户设置的配置。当他按下OK按钮时,会调用“已接受”。在第一时刻,编译器不喜欢rowCount()返回的值,因为它是一个普通的int;我把它的值放在一个const int,“numItems”中。不知道这实际上是否改变了什么,但是数组的声明(selectedItemsX)没有返回任何错误。因此,我希望我可以使用这样的代码。但是当我创建结构“PQDataRequest”时,编译器为其中的“selectedItems”数组提供了该错误。 SAME数组,现在有非const大小的问题!上面代码中显示的第二个结构不会出现任何错误。
那么为什么我可以在结构声明之外声明和使用像selectedItemsX这样的数组,但是我不能在结构中使用完全相同的数组?我怎么能克服这个问题呢?请注意,我不能使用诸如vector之类的可变大小容器,因为稍后需要以类似的方式在C代码中实现相同的算法,并且在结构内使用指向数组的指针是有问题的,因为我'我需要稍后在struct中使用sizeof(),并且我只能在调用accepted()时知道运行时数组的大小。
感谢您的帮助,
Momergil
答案 0 :(得分:2)
uchar selectedItemsX[numItems];
这是一个VLA(可变长度数组,通过一些C ++实现,非标准扩展支持最佳。
让numItems
成为const
与获得这一事实毫无关系。所有这一切都保证一旦初始化numItems
它就不可变。它必须是编译时const 表达式(在这种情况下它不是)。
如果你想要通用的C ++支持(并考虑std::vector<uchar> selectedItemsX
的所有突发特征作为奖励),请使用std::vector<>
,构造初始化到适当的大小。你说,&#34;请注意,我不能使用可变大小的容器,例如vector,因为相同的算法需要稍后在C代码中以类似的方式实现。&#34; C不是C ++ 。您在C中使用的机制使用灵活的数组成员and no such nicety exists in standard C++
答案 1 :(得分:2)
如果您的目标是C然后编写C - 您可以使用C ++编译器进行编译,但此时选择编译为C将避免麻烦。
出现问题是因为数组维度必须是编译时间常量,即编译代码时已知并已修复。正如WhozCraig指出const
只确保一旦numItems
的值设置(在运行时),就无法更改。
您的问题有三种解决方案:
1)对数组大小使用编译时上限常量:
static const int MaxSelectedItems = 128;
typedef struct {
re8k_ict_header header;
re8k_ict_physical_quantity quantity;
uchar selectedItems[MaxSelectedItems];
} PQDataRequest;
绝不能超过MaxSelectedItems数组索引。即设置selectedItems的代码应该检查index < MaxSelectedItems
(请注意,对于此检查下面的其他动态解决方案也会强制执行,因此它并不是真正的缺点)。如果代码是C因为它将继续运行嵌入式这就是要走的路 - 除非有真正的需要,否则你通常不会开始在嵌入式环境中进行mallocing和释放mem。这里唯一真正的缺点是它使用了内存 - 通常这不是问题(甚至嵌入式),并且优先考虑动态内存分配引入的潜在问题。
2)使用指针字段:
typedef struct {
re8k_ict_header header;
re8k_ict_physical_quantity quantity;
uchar* selectedItems;
} PQDataRequest;
对于结构的每次使用,您必须使用malloc并释放selectedItems
字段。
int selectedItemsSize = 20;
PQDataRequest myDataRequest;
myDataRequest.selectedItems = malloc(sizeof(uchar)*selectedItemsSize;
// don't foreget to free myDataRequest.selectedItems when done!
如果你真的必须有动态分配,并且你不打算使用PQDataRequests数组(如果你这样做,请参见下文)。除非严格要求,否则不会真正推荐,因为你有分配的麻烦,更重要的是每次使用struct时释放selectedItems数组。
3)使用C99灵活阵列成员:
typedef struct {
re8k_ict_header header;
re8k_ict_physical_quantity quantity;
uchar selectedItems[];
} PQDataRequest;
如果您计划使用PQDataRequests和数组,建议使用此方法。此方法允许您为WHOLE数组使用malloc(和后者自由)内存:
int dataRequestArraySize = 5;
int selectedItemsSize = 20;
PQDataRequest* my_array = malloc((sizeof(PQDataRequest) + (selectedItemsSize*sizeof(uchar))) * dataRequestArraySize);
而不必为数组中的每个PQDataRequest分配和释放selectedItem。
在上述三种情况中,您还将跟踪所选项目的计数 - 最有可能的是在结构中包含int selectItemsCount
字段。在1)中,这使得能够知道阵列中的哪些值是有效的(&lt;而不是selectItemsCount)以及哪些未被使用(&gt; selectItemsCount但是&lt; MaxSelectedItems)。 2&amp; 3此计数使您可以检查何时读取或写入您未在动态分配大小之外引用的数组。
答案 2 :(得分:1)
struct
的大小必须在编译时确定,以便编译器知道如何使用该类型。因此,尝试使用动态值来声明其中的数组将是非法的。
您在函数体中声明的数组在执行期间在堆栈上创建,因此允许它具有可变大小。
答案 3 :(得分:1)
在c ++中创建数组时,需要知道compile_time的大小。如果无法确定,则无法创建。
一种可能的解决方案是在动态内存中创建数组。我建议您查看http://www.cplusplus.com/reference/new/operator%20new[]
这将允许你做你想做的事,但你应该记得以后释放你的记忆!
sizeof()不应该是必需的,因为你可以将数组的元素数量保持在一个单独的值中,然后将它与sizeof(array [0])相乘
答案 4 :(得分:0)
问题是第一个结构的大小在编译时是不可知的,而且不合法。您不能拥有动态大小的结构,否则在编译时无法静态确定sizeof(struct PQDataRequest)
之类的内容。
很抱歉,如果您需要在结构内部使用动态大小的元素,则必须将其保留为指针,然后在创建时动态分配数组。
答案 5 :(得分:0)
并且在结构体内使用指向数组的指针是有问题的,因为我稍后需要在结构中使用sizeof()
但是,您仍然可以使用指向数组的指针,并且还将size_t设置为numItems,这可用于在代码中稍后确定数组的长度。