新数组,从另一个指向字符串的指针数组衍生而来,只是顺序不同以C表示

问题描述

如果可能的话,我正在寻求数组和指针的帮助...

我已经定义了一些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常量表达式

...

  1. 地址常量是一个空指针,一个指向左值的指针,该左值指定一个静态存储持续时间的对象,或者一个指向函数指示符的指针;它应使用一元&运算符或强制转换为指针类型的整数常量显式创建,或使用数组或函数类型的表达式隐式创建。 数组下标[] 和成员访问权限.->运算符,地址&和间接访问*一元运算符,指针强制转换可以用于创建地址常量,但是不能使用这些运算符来访问对象的值。

您的变体几乎可以使用,但是您需要添加运算符的地址:

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是字符串长度,可以在编译时预先计算。