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

时间:2015-06-05 18:17:57

标签: c arrays struct extern static-array

我正在尝试链接静态定义的结构数组。我正在使用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没有正确链接(nm输出中的位置与实际程序打印的位置不同)。

注意:我不能在main.c中包含test.c文件。必须联系起来。

2 个答案:

答案 0 :(得分:3)

更改

extern my_struct* my_array;

extern my_struct my_array[];

您无法使用extern将数组修改为指针。

答案 1 :(得分:3)

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

短:

  • struct x * p; // p是存储在x中的值:“它指向的地方”
  • struct x q []; // q是第一个条目的地址(==数组的地址)。

为了获得相同的p,你实际上必须采用&p,但这将是指向指针的类型指针,而不是结构。这是数组和指针之间的差异之一。有关详细信息,请阅读standard

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

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

有一个例外:如果让链接器将程序重定位到绝对地址,例如裸机(没有完全成熟的OS)嵌入式控制器,nm将报告与运行期间相同的地址-time或在调试器中。原因是链接器实际上包含上述运行时加载器的作业。结果,代码必须加载到正确的地址范围,例如,到闪存。