2

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

这是我所拥有的:

类型.h:

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

测试.c:

include "type.h"

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

主.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)

nm 输出中 my_array 的地址:

0000000000601060 D my_array

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

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

4

2 回答 2

4

改变

extern my_struct* my_array;

extern my_struct my_array[];

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

于 2015-06-05T18:21:40.627 回答
3

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

短的:

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

要为 p 获得相同的值,您实际上必须采取&p,但这将是指向指针的类型,而不是结构。这是数组和指针之间的区别之一。详细阅读标准

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

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

有一个例外:如果您让链接器将程序重定位到绝对地址,例如裸机(没有成熟的操作系统)嵌入式控制器,nm则应报告与运行时或调试器中相同的地址。原因是链接器实际上包含了上述运行时加载器的工作。因此,代码必须加载到正确的地址范围,例如闪存。

于 2015-06-05T18:30:25.130 回答