You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在编译时让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:23:17