我有可能是一个声明问题:

我声明了const int数组:

const int my_array[] = {
    // data...
}

然后,我需要声明以下形式的另一个字节数组:
00 aa 01 bb 02 cc

其中aabbcc是const int内存中的24位地址(我精确地为一个非常特殊的平台编写了代码,这解释了这一点),所以我写道:
const char my_other_array[] = {
    00, (my_array >> 16) & 0xFF, 01, (my_array >> 8) & 0xFF, 02, my_array & 0xFF
}

但我得到这个错误:
error: invalid operands to binary >>
error: initializer element is not constant

我考虑过类型转换my_array:
const char my_other_array[] = {
    00, (((const u32) my_array) >> 16) & 0xFF, 01, (((const u32) my_array) >> 8) & 0xFF, 02, ((const u32) my_array) & 0xFF
}

但是然后我得到一个警告+错误:
warning: initializer element is not computable at load time
error: initializer element is not computable at load time

我究竟做错了什么 ?

对于那些询问的人,这是实际的代码(我切掉了不相关的部分):
#include <genesis.h>
#include "snake.h"

const u32 snake_patterns[] = {
    0x00024666,
    // ... some 100ths of lines
};

const u16 temp[] = {
    1, 0x9370, 0x9400, ((const u32) snake_patterns) & 0xFF, (((const u32) snake_patterns) >> 8) & 0xFF, (((const u32) snake_patterns) >> 16) & 0xFF
};

您会注意到事情有些复杂,但是我认为前面的基本示例(用适当的括号固定)以更清楚的方式显示了问题。有些人可能会识别出Genesis VDP的DMA调用列表。

最佳答案

用于初始化数组的元素必须是常量表达式。这些在the C99 standard的6.6节中定义,或在C11中的相同位置定义。见第7段:



现在my_array是一个地址常量,但是您所要做的就是加或减一个整数常量。通过移位或屏蔽,您正在创建的内容不再是常量表达式,因此在初始化程序中是不允许的。

我猜想此限制的理由是C旨在用于可重定位代码,在这种情况下,程序在内存中的位置可能要等到为执行而加载时才知道。在这样的系统上,加载程序必须根据程序在加载时读取的二进制表中的内容来填写对程序中地址的引用(例如,“在程序中的相对地址0x12345678处,填写程序的绝对地址一旦知道对象my_array”)。该表通常具有相当严格的格式,并且可能具有表达常量偏移量的方式(“填写对象my_array的绝对地址,加上42”),但通常不支持任意算术。

可能最简单的解决方案是编写一个函数以提取my_other_array地址的必要位并将其插入const,然后在需要使用my_array之前调用此函数,以使my_other_array不再是my_other_array并在运行时填充它。 。

如果出于某种原因很重要,则在加载程序时已经填写了my_other_array,并且您的目标平台使您知道该程序将位于内存中的位置,则可以使用汇编程序或链接程序的功能。实现您想要的。但这当然是特定于系统的。

(编辑:您在另一条评论中提到该数组需要放入ROM。如果是这样,那么我认为我的最后建议是您唯一的希望。您可能想提出另一个问题,关于如何/是否可以使用您正在使用的特定工具链。)

关于c - 常量数组的声明,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36182463/

10-15 08:48