链接外部静态结构数组无法正常工作

Linking an extern static array of structs is not working correctly

我正在尝试 link 一个静态定义的结构数组。我正在使用 extern 修饰符来这样做。当我打印出 extern 结构的内存地址时,它与它在可执行文件中的位置不同。

这是我的:

type.h:

typedef struct tableEntry {
     const char *my_str;
     void *my_addr;
     int myint;
} my_struct;

test.c:

include "type.h"

my_struct my_array[] = {
    {"hello", (void*)15, 5000},
    {"world", (void*)15, 3000},
    {"abtest", (void*)15, 2000},
};

main.c:

#include <stdio.h>
#include "type.h"

extern my_struct* my_array;

int main() {
    printf("array location - %p\n", my_array);
    printf("array entry 1 myint - %d\n", my_array[0].myint);
    printf("array entry 1 address - %p\n", my_array[0].my_addr);
    printf("array string location - %p\n", &(my_array[0].my_str));
    printf("array string - %s\n", my_array[0].my_str);
}

我是这样编译程序的:

gcc test.c main.c

当我 运行 我的可执行文件时,我得到以下输出:

array location - 0x4006be
array entry 1 myint - 29811
array entry 1 address - 0x6574626100646c72
array string location - 0x4006be
Segmentation fault (core dumped)

my_array 在 nm 输出中的地址:

0000000000601060 D my_array

如您所见,我的输出不是我所期望的,并且 my_array 没有正确 linked(nm 输出中的位置与实际程序打印的位置不同) .

注意:我不能在我的 main.c 中包含 test.c 文件。必须 linked.

改变

extern my_struct* my_array;

extern my_struct my_array[];

您不能使用 extern 将数组修改为指针。

my_array 地址的问题是您打印 指针 包含 。但是对于数组,您需要指针本身的地址(这将是数组第一个元素的地址)。然而,作为一个指针,它仍然被错误地声明(想知道为什么编译器没有抱怨)。

短:

  • 结构x *p; // p 是存储在 x 中的值:"where it points to"
  • 结构xq[]; // q 是第一个条目的地址(== 数组的地址)。

要获得相同的 p,您实际上必须采用 &p,但那将是指向指针的指针类型,而不是结构。这是数组和指针的区别之一。阅读 standard 了解详情。

因此,使用您在 main.c 中的实现文件中使用的相同声明。实际上,您应该将声明打包到 header type.h 中(注意这很容易与标准的 header type**s**.h 混淆)。当您编译“type.c”时,它还会生成有关声明和定义不匹配的警告。这实际上是 header 最重要的用途之一。

对于实际地址与逻辑地址之间的差异nm报告:文件加载到RAM之前执行并且必须根据加载地址重定位。文件中的地址实际上是相对于 .data(已初始化变量)或 .bss(未初始化,默认为 0 个变量)部分的基地址而言的,通常文件中的每个部分都是 0。加载时,将RAM中的起始地址与这些相对地址相加得到实际地址。这是程序加载后可能需要一些时间的原因之一(重定位可能非常复杂)。

有一个例外:如果您让链接器将程序重定位到绝对地址,例如 bare-metal(没有 full-grown OS)嵌入式控制器,nm 应报告与 run-time 期间或调试器中相同的地址。原因是链接器实际上包含了上述 run-time 加载器的工作。因此,代码必须加载到正确的地址范围,例如到闪存。