[英]Initialization of a pointer array
我在用指向结构成员的指针初始化数组时遇到问题。 必须通过结构指针访问结构成员。 这样做的原因是我们在运行时初始化了指向内存映射地址位置的指针。 以下代码段是问题的一个示例;
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
long* lp;
}T;
typedef struct
{
long l;
}F;
F* f;
T t[] =
{
{ &f->l }
};
void init (void)
{
f = (F*) 0x08000100;
}
int main (void)
{
init();
return EXIT_SUCCESS;
}
编译器输出如下:
\n gcc -O0 -g3 -Wall -c\n -fmessage-length = 0 -osrc \\ Test.o .. \\ src \\ Test.c .. \\ src \\ Test.c:18: \n 错误:初始化元素不是恒定的\n .. \\ src \\ Test.c:18:错误:(在“ t [0] .lp”的初始化附近)\n .. \\ src \\ Test.c:18:错误:初始化元素不是恒定的\n .. \\ src \\ Test.c:18:错误:(在t [0]的初始化附近) \n 发生构建错误,构建已停止\n
这里的问题是我们在运行时初始化指针,编译器不知道在哪里可以找到结构成员。 我们无法解决结构指针,因为我们不想为此使用链接程序脚本。
任何想法如何解决这个问题?
T t[] =
{
{ &f->l }
};
元素的地址(例如&f-> l)仅在运行时知道。
这样的值不能用于编译时初始化(这是在此处进行的操作)。
t []数组要等到运行时才能填写-因为直到运行时才知道F的地址。
您可以将T []初始化为{NULL}并在初始化后对其进行修补。
另一种方法是将T的成员初始化为只是结构内的偏移量,然后在初始化f之后,遍历数组并通过添加f的地址来调整指针位置。 此技术类似于链接中经常使用的技术。
像这样:
#define MEMBER_OFFSET_OF(a,b) &(((a*)0)->b)
T t[] =
{
{(long*)MEMBER_OFFSET_OF(F, l)}
};
const int numElementsInT = sizeof(t) / sizeof(t[0]);
void init()
{
f = (F*) 0x08000100;
for (int i= 0; i < numElementsInT; i++)
{
t[i].lp += (unsigned int)f;
}
}
从技术上讲,对于C90编译器而言,这是无法解决的。 对于初始化习语,
声明符 = 初始化序列
初始化序列必须是一个常量表达式,即可以在编译时或链接时计算的一个常量表达式。 所以,
int a;
int *b[] = { &a };
工作,而
void foo() {
int a;
int *b[] = { &a };
}
不会因为在运行时之前无法计算自动地址a的地址。
如果切换到C99,则后者可以使用。 但是,您的代码仍然超出了C99编译器可以预计算的范围。 如果切换到C ++,您的代码将正常运行,至少Comeau不反对。 编辑:Roger当然是正确的,因为这不能解决通过NULL指针进行不正确的取消引用的问题。
假设您可以使用非恒定数据初始化全局变量:您仍然遇到很大的问题。
当t初始化时,f仍然具有不确定的值:这发生在 init()执行并分配魔术地址之前。 因此,即使您可以使用&f->l
,也无论如何都必须重置它的所有使用位置。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.