【问题标题】:Write half address to structure at compiling/linking time在编译/链接时将半地址写入结构
【发布时间】:2013-10-15 13:48:31
【问题描述】:

我写了代码:

#include <inttypes.h>

int vari;

#if 1
struct xx {
  uint16_t p_vari;
} st ={
  .p_vari=(uint16_t)(uintptr_t)&vari,
};
#else
struct xx {
  void *p_vari;
} st ={
  .p_vari=&vari,
};
#endif


int main(void) {

  return 0;
}

如果我尝试将地址的前 16 位写入结构, (代码的第一个变体)我得到了:

  vari.c:9:3: error: initializer element is not constant
  vari.c:9:3: error: (near initialization for 'st.p_vari')

如果我将地址写在 void*(代码的第二个变体)上,gcc 编译成功。

如何制作第一个变体?

我需要它,因为 gcc 不能使用 16 位寻址, 但我需要生成包含 16 位地址的结构。 我想在链接或编译时得到结果。

【问题讨论】:

  • 也许可以尝试使用带有void*uint16_t 字段的联合

标签: c gcc 16-bit


【解决方案1】:

在 32 位(或 64 位程序)中没有 16 位寻址这样的东西。地址始终具有相同的大小,这取决于架构。

这里的问题是链接器只能进行特定的地址操作,不能进行任意计算。
当变量保存静态地址时,编译器将其标记为静态地址。然后链接器和加载器知道根据真实地址更新它。但他们所能做的只是放入一个地址 - 而不是获取地址并对其进行操作(例如丢弃位)。

【讨论】:

  • C 标准没有规定不同类型的指针具有相同的大小,即使在一个程序中也是如此。一个 C 实现可能有不同大小的指针。
  • @EricPostpischil,您是对的,尽管它并没有真正影响答案。在大多数 32 位架构中,没有 16 位指针之类的东西。
  • 问题中的故意代码仅提取地址的 16 位表明 OP 在寻址方面有特殊需求。因此,对目标平台上的寻址做出假设还为时过早。
  • 也许我可以在链接器脚本中设置这个值?
【解决方案2】:

您的问题是编译器/链接器初始化了全局变量。

编译器了解何时必须使用仅在链接时才知道的地址初始化 void *,但当您尝试在编译时执行此操作时它不了解它,就像 uint16_t 的情况一样.尝试使用联合:

union xx {
  uint16_t p_vari_16;
  void * p_vari_p;
} st ={
  .p_vari_p=&vari
};

但请注意,这只会在小端架构上产生正确的结果。在 main 中使用初始化程序以获得最大的可移植性。

【讨论】:

  • 好变种。但是,如果我初始化 p_vari_p,然后我在下半部分 (&p_vari_16+1) 写入(也在 init 上),我会丢失前半部分 (p_vari_16)。
猜你喜欢
  • 2015-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-15
  • 1970-01-01
  • 1970-01-01
  • 2013-12-07
  • 1970-01-01
相关资源
最近更新 更多