C 如何鼓励';地址';对链接器变量的访问

C 如何鼓励';地址';对链接器变量的访问,c,linker-scripts,C,Linker Scripts,正如在“从源代码访问链接器脚本定义的变量是不直观的”中所讨论的,从本质上讲,访问它们的值通常不是您想要的(因为它们实际上没有分配内存块,作为真正的编译器变量),并且仅通过地址访问它们。是否有一个属性可以在声明时应用于变量,或者可能有一个PC Lint/静态分析属性/规则可以应用于变量 /* Linker config (.icf) file */ define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; define symbol __I

正如在“从源代码访问链接器脚本定义的变量是不直观的”中所讨论的,从本质上讲,访问它们的值通常不是您想要的(因为它们实际上没有分配内存块,作为真正的编译器变量),并且仅通过地址访问它们。是否有一个属性可以在声明时应用于变量,或者可能有一个PC Lint/静态分析属性/规则可以应用于变量

/* Linker config (.icf) file */
define symbol __ICFEDIT_region_ROM_start__  = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__    = 0x080FFFFF;

define symbol __ICFEDIT_region_ROM_size__ = (__ICFEDIT_region_ROM_end__ - __ICFEDIT_region_ROM_start__) + 1;
export symbol __ICFEDIT_region_ROM_start__;
export symbol __ICFEDIT_region_ROM_size__;
/*main.c*/
void OS_SetROM(uint32_t start,uint32_t size){}//空,仅用于演示
内部主(空)
{
外部无符号整数、ICFEDIT、区域、ROM、开始;
外部无符号整数uu ICFEDIT u区域u ROM uuu大小uuu;
//不正确-两者可能都读为“0”,具体取决于这些位置中的实际内容
//我可以得到有关此用法的警告或错误吗?
OS_SetROM(uuu ICFEDIT_region_ROM_start_uu,uu ICFEDIT_region_ROM size_u);
//正确-*链接器定义变量的*地址已读取
OS_SetROM((uint32_t)和ICFEDIT_region_ROM_start_,(uint32_t)和ICFEDIT_region_ROM size_);
将地址声明并作为指针(如下所示)使用会很好,也就是说,您可以使用指针变量的值来表示地址,“value of”语义更有意义(至少在逻辑上-更明显的是,在这种情况下您不会取消引用),但它们不是这样工作的-为此,链接器还必须分配一个内存位置并将地址存储在那里,或者编译器/链接器的一些特殊语义,这似乎是不可能的

void void OS_SetROM(uint32_t*const start,uint32_t size){}//空,仅用于演示
内部主(空)
{
//很好,但不是它的工作原理
外部无符号整数*常量ICFEDIT区域ROM开始;
外部无符号整数常量ICFEDIT区域ROM大小;
OS_SetROM(uuu ICFEDIT_region_ROM_start_uu,uu ICFEDIT_region_ROM size_u);
一种折衷方法是用适当的类型ala重新定义这些变量:

unsigned int*const p_rom_start=&&u__ICFEDIT_region_rom_start;
unsigned int const rom_size=(unsigned int)和ICFEDIT_region_rom_size;
void OS_SetROM(无符号整数*常数p_开始,无符号整数大小);
OS_设置rom(p_rom_开始,rom_大小);
这有助于将“非直观”访问收集到一个位置,然后键入安全访问,但在这种情况下,这是不可能的,因为API预定义为需要uint32


我意识到这可能不常见(如果有的话,在一个项目中可能只使用过几次),我意识到这也取决于使用属性(例如,在创建一个新项目时),但我很好奇,是否有保护措施可以防止意外误用,或者防止不正确的“简化”(例如,一些维护者不理解其含义)……我也不能想到另一种实施“只访问地址”的方案是有意义的,所以解决方案可能不存在……< /P> < P>你不应该把C++和C放在同一个问题中,它们是不同用途的不同语言。 至少在C中,声明它们为:

extern char ROMStart[], ROMEnd[];  /* shortforms are less clumbsy */
给你很多你想要的:

OS_SetROM(ROMStart, ROMEnd, ROMEnd-ROMStart); /* not sure why the last one */
尽管聪明的半编译器可能会抱怨,如果您试图将这些位置视为对齐的短边或长边,那么为了缓和它们,您可能会:

extern long ROMStart[], ROMEnd[];
intptr_t size = (intptr_t)ROMEnd - (intptr_t)ROMStart;
OS_SetROM(ROMStart, ROMEnd, size);

在C++中,你必须查阅语言标准DU分钟。

< P>你不应该把C++和C放在同一个问题中,它们是不同的语言,用于不同的目的。 至少在C中,声明它们为:

extern char ROMStart[], ROMEnd[];  /* shortforms are less clumbsy */
给你很多你想要的:

OS_SetROM(ROMStart, ROMEnd, ROMEnd-ROMStart); /* not sure why the last one */
尽管聪明的半编译器可能会抱怨,如果您试图将这些位置视为对齐的短边或长边,那么为了缓和它们,您可能会:

extern long ROMStart[], ROMEnd[];
intptr_t size = (intptr_t)ROMEnd - (intptr_t)ROMStart;
OS_SetROM(ROMStart, ROMEnd, size);

在C++中,你必须查阅语言标准DU分钟。

< p>你可以为一个不完整类型的对象声明一个标识符,比如一个未给出定义的结构:

extern struct NeverDefined __ICFEDIT_region_ROM_start__;

然后您可以获取它的地址,但尝试使用或分配它将产生编译器错误。

您可以为类型不完整的对象声明标识符,例如未给出定义的结构:

extern struct NeverDefined __ICFEDIT_region_ROM_start__;

然后你可以使用它的地址,但是尝试使用或分配它会产生编译器错误。

我已经删除了C++< /Calp>标签;我们在嵌入式中使用C++,但在这里没有特别说明,所以保持它是“<代码> C++ <代码>的意义;也删除了代码> LIt< <代码>标签,两者都不是(当前)答案指定任何lint用法。从类型的角度来看,我喜欢这个答案。我没有想到使用数组名作为ptr功能,但它很聪明,有助于类型比另一个答案中的“struct”更有意义),而且它仍然“有效”(正确)即使您关闭了
&
。也可以使用此表单(
long start=ROMStart[0]
)获取地址处的值,但这显然不是偶然的。这也是从源代码访问链接器变量的一些(更新的)参考中推荐的表单。(请参阅链接q)我已经删除了 C++< /Cult>标签;我们在嵌入式中使用C++,但在这里没有特别说明,所以保持它是“<代码> C++ <代码>的意义;也删除了代码> LIt< <代码>标签,两者都不是(当前)答案指定任何lint用法。从类型的角度来看,我喜欢这个答案。我没有想到使用数组名作为ptr功能,但它很聪明,有助于类型比另一个答案中的“struct”更有意义),而且它仍然“有效”(正确)即使您关闭了
&
。也可以使用此表单(
long start=ROMStart[0]
)获取地址处的值,但这显然不是偶然的。这也是从源代码访问链接器变量的一些(更新的)参考中推荐的表单。(请参阅链接q)另请参见&另请参见&此操作有效,如果执行此操作,将导致类型错误