问题描述
如果可能的话,我正在寻求数组和指针的帮助...
我已经定义了一些const字符串:
static const Int8U item1[] = {0x4D,0x61,0x72,0x74,0x65,0x6C,0x20,0x4D,0x43,0x50,0x37,0x38,0x31,0x30,0x00};
static const Int8U item2[] = {0x4D,0x00};
static const Int8U item3[] = {0x4D,0x00};
我在指针数组中引用这些字符串:
const Int8U* original_sequence[] =
{
item1,item2,item3
}
#define SEQUENCE_ELEMENT_1 (0)
#define SEQUENCE_ELEMENT_2 (1)
#define SEQUENCE_ELEMENT_3 (2)
我可以通过类似于以下内容的方式引用任何字符串:
original_sequence[SEQUENCE_ELEMENT1]
到目前为止一切都很好。但是,还有另一种配置,它由相同的项目组成,只是顺序不同。理想情况下,我想在全局范围内声明以下内容:
const CHAR *new_sequence[3] =
{
original_sequence[SEQUENCE_ELEMENT_2],original_sequence[SEQUENCE_ELEMENT_1],original_sequence[SEQUENCE_ELEMENT_3]
};
但是我收到错误消息“表达式必须具有恒定值”。请注意,由于#defines是标识中的关键,因此我无法直接引用'item1'等。
我也尝试过这样的变体,例如:
const CHAR **new_sequence[3] =
{
(char**)original_sequence[SEQUENCE_ELEMENT_2].
(char**)original_sequence[SEQUENCE_ELEMENT_1].
(char**)original_sequence[SEQUENCE_ELEMENT_3]
};
似乎什么也无济于事。如果我将自己与指针混淆,或者犯了编译器限制,我将无法解决?让我觉得没有限制的是,如果我直接在这个新数组中引用'item1'字符串,我认为不会有问题。
谢谢
Rob
解决方法
很遗憾,标准C语言不允许您尝试做的事情。
C17草案解释说,您不能在地址常量表达式中使用对象的值:
6.6常量表达式
...
- 地址常量是一个空指针,一个指向左值的指针,该左值指定一个静态存储持续时间的对象,或者一个指向函数指示符的指针;它应使用一元
&
运算符或强制转换为指针类型的整数常量显式创建,或使用数组或函数类型的表达式隐式创建。 数组下标[]
和成员访问权限.
和->
运算符,地址&
和间接访问*
一元运算符,指针强制转换可以用于创建地址常量,但是不能使用这些运算符来访问对象的值。
您的变体几乎可以使用,但是您需要添加运算符的地址:
const CHAR **new_sequence[3] =
{
(char**)&original_sequence[SEQUENCE_ELEMENT_2],(char**)&original_sequence[SEQUENCE_ELEMENT_1],(char**)&original_sequence[SEQUENCE_ELEMENT_3]
};
但是,它有一个缺点,您需要在使用时进一步取消引用:
*new_sequence[index]
我只需将SEQUENCE_ELEMENT_ *常量放入纯整数数组中,并使用函数隐藏访问细节,并在需要new_sequence元素时调用此函数:
uint8_t new_sequence[] = {
SEQUENCE_ELEMENT_2,SEQUENCE_ELEMENT_1,SEQUENCE_ELEMENT_3
};
char * get_new_sequence_text(int index) {
return (char*)original_sequence[new_sequence[index]];
}
,
该错误消息已经告诉您,这是什么问题。从另一个变量/数组派生值时,初始化元素必须是常量值,情况并非如此。另请参见Initialization
初始化具有静态或线程本地存储持续时间的对象时,初始化器中的每个表达式都必须是恒定表达式或字符串文字。
所以初始化它的唯一方法是使用常量值,例如
Flexible
或在函数内完成
const Int8U *new_sequence[3] =
{
item2,item1,item3
};
或通过代码动态执行
void func()
{
const Int8U *new_sequence[3] =
{
original_sequence[SEQUENCE_ELEMENT_2],original_sequence[SEQUENCE_ELEMENT_1],original_sequence[SEQUENCE_ELEMENT_3]
};
}
或具有其他间接方案
new_sequence[0] = original_sequence[SEQUENCE_ELEMENT_2];
new_sequence[1] = original_sequence[SEQUENCE_ELEMENT_1];
new_sequence[2] = original_sequence[SEQUENCE_ELEMENT_3];
并通过int new_sequence_index[] =
{
SEQUENCE_ELEMENT_2,SEQUENCE_ELEMENT_3
};
等进行访问。
实际上,有两个问题:
- 您的数据集具有不同的长度,这意味着您必须使用指针和大小,而不仅仅是创建所有内容的大型多维数组(这将更简单,更有效)。
- 您不能在静态存储持续时间(“全局”等)的对象的初始化列表中引用非常量表达式的内容。可以使用其他变量的地址,但不能使用这些变量的值。
要解决此问题,理论上您可以创建一些棘手的指针到指针表,但是语法会很快变得混乱。一种不太晦涩的替代方法可能是创建一个数据集,然后创建索引表而不是指针表。
例如,您可以执行以下操作:
#define ITEM1 0x4D,0x61,0x72,0x74,0x65,0x6C,0x20,0x4D,0x43,0x50,0x37,0x38,0x31,0x30,0x00
#define ITEM2 0x4D,0x00
#define ITEM3 0x4D,0x00
static const uint8_t* const data[3] =
{
(const uint8_t[]) { ITEM1 },(const uint8_t[]) { ITEM2 },(const uint8_t[]) { ITEM3 },};
(每个人都应该摆脱标准的C stdint.h支持的讨厌的自制类型。)
这将创建一个指向3个只读数组的只读指针表。每个数组与指针表本身具有相同的作用域。您可以执行此操作以创建具有不同顺序的多个表,但这会创建大量开销数据。因此,可以考虑使用这种方法:
enum
{
SEQUENCE_ELEMENT_1,SEQUENCE_ELEMENT_2,SEQUENCE_ELEMENT_3,};
static const size_t original_sequence[3] =
{
SEQUENCE_ELEMENT_1,};
static const size_t new_sequence[3] =
{
SEQUENCE_ELEMENT_2,};
您现在拥有一组数据,可以通过以下方式访问:
for(size_t i=0; i<3; i++)
{
for(size_t j=0; i<something; j++)
{
uint8_t a = data[ original_sequence[i] ][j];
...
}
}
然而,拼图的缺失部分是存储每个项目集合的各个大小的位置。我假设它们是字符串,在这种情况下,上面的something
是字符串长度,可以在编译时预先计算。