如何在编译时让C代码复用链接脚本中的内存区域大小定义
问题描述
链接脚本内容
... _other_start = ORIGIN(OTHER); _other_end = ORIGIN(OTHER) + LENGTH(OTHER); _other_size = LENGTH(OTHER); ... /* Memories definition */ MEMORY { ... OTHER (rw) : ORIGIN = 0xC000000, LENGTH = 1MB ... } ...
原C代码与编译警告
void fun() { extern char _other_start; char *ptr = &_other_start; char tmp[10]; for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } }
使用GCC编译时会抛出警告:
warning: '__builtin_memcpy' reading 10 bytes from a region of size 1 [-Wstringop-overflow=]
将代码修改为以下形式可消除警告,但需要手动指定数组大小:
void fun() { extern char _other_start[10]; char *ptr = &_other_start; char tmp[10]; for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } }
核心疑问
能否在编译时让extern char _other_start的缓冲区大小直接复用链接脚本中定义的内存区域大小,无需在代码中通过宏重复定义?比如想实现类似下面的效果(当前写法不可行):
#define OTHER_SIZE = 1024 * 1024 // 不想这么做,属于重复定义 #define OTHER_SIZE = _other_size // 想复用链接脚本中的值,但写法无效 void fun() { extern char _other_start[OTHER_SIZE]; char *ptr = &_other_start; char tmp[10]; for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } }
解决方案
可以通过以下几种方式实现链接脚本与C代码的尺寸复用,避免重复定义:
1. 利用链接脚本导出符号结合柔性数组
链接脚本中已经定义了_other_size符号,可在C代码中声明该符号,再通过结构体包装柔性数组间接告知编译器内存区域的存在:
#include <stddef.h> // 声明链接脚本导出的尺寸符号 extern const unsigned long _other_size; // 用结构体包装柔性数组,链接时自动匹配实际内存区域大小 typedef struct { char data[]; } OtherRegion; // 声明外部区域起始地址,强制转换为结构体类型 extern OtherRegion _other_start; void fun() { char *ptr = _other_start.data; char tmp[10]; for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } }
如果需要编译时校验尺寸,可使用C11的static_assert(需编译器支持):
#include <assert.h> static_assert(_other_size >= 10, "OTHER region size is insufficient!");
2. 自动化生成头文件
通过脚本从链接脚本中提取内存区域长度,自动生成头文件供C代码引用,彻底避免重复定义:
- 编写脚本(如Shell/Python),从链接脚本中提取
LENGTH(OTHER)的数值。 - 生成包含尺寸宏的头文件,示例Shell脚本:
# 从链接脚本提取OTHER区域长度并转换为数值 OTHER_SIZE=$(grep -o 'LENGTH = [0-9A-Z]*' link.ld | awk '{print $3}' | sed 's/MB/*1024*1024/') # 生成头文件 echo "#define OTHER_SIZE $OTHER_SIZE" > memory_regions.h
- 在C代码中包含该头文件,即可直接使用
OTHER_SIZE定义数组:
#include "memory_regions.h" void fun() { extern char _other_start[OTHER_SIZE]; char *ptr = &_other_start; char tmp[10]; for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } }
3. GCC扩展:用__builtin_object_size抑制警告
利用GCC内置函数__builtin_object_size告知编译器指针指向区域的实际大小,从而消除溢出警告:
extern char _other_start; extern const unsigned long _other_size; void fun() { char *ptr = &_other_start; char tmp[10]; // 告知编译器当前指针指向区域的最小可用尺寸 if (__builtin_object_size(ptr, 0) >= 10) { for(int i = 0; i < 10; i++) { tmp[i] = *ptr++; } } }
内容的提问来源于stack exchange,提问作者kokopelli
相关产品推荐
相关产品推荐

