除宏定义外,C/C++中是否存在拼接常量数组的方法?
C/C++ 非宏方式拼接常量数组方案
需求场景
需要声明包含共享片段的常量数组,当前通过宏定义实现拼接,希望找到非宏的替代方案。
期望的理想代码(无法编译)
struct Param{int a; int b;}; const static std::vector<Param> SHARED_DATA = { {1,2}, {3,4}, }; const static std::vector<Param> TEST_DATA_ONE = { {5,6}, SHARED_DATA, {7,8}, }; const static std::vector<Param> TEST_DATA_TWO = { {9,10}, SHARED_DATA, {11,12}, };
当前宏实现代码
#define SHARED_DATA \ {1,2}, \ {3,4} #define TEST_DATA_ONE \ {5,6}, \ SHARED_DATA, \ {7,8} \ #define TEST_DATA_TWO \ {9,10}, \ SHARED_DATA, \ {11,12} \ const Param PACK_DATA_ONE[] = { TEST_DATA_ONE, {1,2}, }; const Param PACK_DATA_TWO[] = { TEST_DATA_TWO, {1,2}, };
C++ 解决方案
C++可借助标准库容器和编译时特性实现灵活拼接,无需依赖宏。
1. 运行时容器拼接(C++11及以上)
通过通用辅助函数合并多个容器或初始化列表,适配大多数常规场景:
#include <vector> #include <algorithm> struct Param{int a; int b;}; const static std::vector<Param> SHARED_DATA = {{1,2}, {3,4}}; // 支持任意数量容器/初始化列表的拼接函数 template<typename... Containers> std::vector<Param> concat(Containers&&... containers) { std::vector<Param> result; // 依次插入各容器的元素 (result.insert(result.end(), std::begin(containers), std::end(containers)), ...); return result; } // 定义目标数组 const static std::vector<Param> TEST_DATA_ONE = concat( std::vector<Param>{{5,6}}, SHARED_DATA, std::vector<Param>{{7,8}} ); const static std::vector<Param> TEST_DATA_TWO = concat( std::vector<Param>{{9,10}}, SHARED_DATA, std::vector<Param>{{11,12}} );
2. 编译时常量拼接(C++20及以上)
利用constexpr特性在编译阶段完成拼接,生成真正的常量容器:
#include <vector> #include <array> struct Param{int a; int b;}; // 用std::array存储编译时共享数据 constexpr std::array<Param, 2> SHARED_DATA = {{1,2}, {3,4}}; // 编译时生成TEST_DATA_ONE的函数 constexpr std::vector<Param> make_test_data_one() { std::vector<Param> v; v.reserve(1 + SHARED_DATA.size() + 1); // 预分配空间提升效率 v.push_back({5,6}); for (const auto& p : SHARED_DATA) { v.push_back(p); } v.push_back({7,8}); return v; } // 编译时初始化常量容器 constexpr static std::vector<Param> TEST_DATA_ONE = make_test_data_one(); // TEST_DATA_TWO同理实现 constexpr std::vector<Param> make_test_data_two() { std::vector<Param> v; v.reserve(1 + SHARED_DATA.size() + 1); v.push_back({9,10}); for (const auto& p : SHARED_DATA) { v.push_back(p); } v.push_back({11,12}); return v; } constexpr static std::vector<Param> TEST_DATA_TWO = make_test_data_two();
C 语言解决方案
C语言无原生容器支持,可通过运行时内存操作或编译器扩展实现拼接:
1. 运行时动态拼接数组
通过malloc和memcpy在运行时合并数组,适合允许动态内存分配的场景:
#include <stdlib.h> #include <string.h> typedef struct {int a; int b;} Param; // 共享数据 const Param SHARED_DATA[] = {{1,2}, {3,4}}; const size_t SHARED_SIZE = sizeof(SHARED_DATA) / sizeof(Param); // 各分段数据 const Param PART_ONE_1[] = {{5,6}}; const size_t PART_ONE_1_SIZE = sizeof(PART_ONE_1) / sizeof(Param); const Param PART_ONE_2[] = {{7,8}}; const size_t PART_ONE_2_SIZE = sizeof(PART_ONE_2) / sizeof(Param); const Param PART_TWO_1[] = {{9,10}}; const size_t PART_TWO_1_SIZE = sizeof(PART_TWO_1) / sizeof(Param); const Param PART_TWO_2[] = {{11,12}}; const size_t PART_TWO_2_SIZE = sizeof(PART_TWO_2) / sizeof(Param); // 拼接三个数组的工具函数 Param* concat_arrays(const Param* arr1, size_t size1, const Param* arr2, size_t size2, const Param* arr3, size_t size3) { size_t total_size = size1 + size2 + size3; Param* result = malloc(total_size * sizeof(Param)); if (!result) return NULL; memcpy(result, arr1, size1 * sizeof(Param)); memcpy(result + size1, arr2, size2 * sizeof(Param)); memcpy(result + size1 + size2, arr3, size3 * sizeof(Param)); return result; } // 使用示例 int main() { Param* TEST_DATA_ONE = concat_arrays(PART_ONE_1, PART_ONE_1_SIZE, SHARED_DATA, SHARED_SIZE, PART_ONE_2, PART_ONE_2_SIZE); // 使用数组逻辑... free(TEST_DATA_ONE); // 记得释放内存 Param* TEST_DATA_TWO = concat_arrays(PART_TWO_1, PART_TWO_1_SIZE, SHARED_DATA, SHARED_SIZE, PART_TWO_2, PART_TWO_2_SIZE); // 使用数组逻辑... free(TEST_DATA_TWO); return 0; }
2. 编译器扩展实现编译时拼接(GCC专属)
利用GCC的__attribute__((section))扩展,将数组放入同一内存段,通过指针范围访问,仅适用于GCC编译器,无跨平台性:
typedef struct {int a; int b;} Param; // 将数组放入自定义内存段 const Param PART_ONE_1[] __attribute__((section("test_data_one"))) = {{5,6}}; const Param SHARED_DATA[] __attribute__((section("test_data_one"))) = {{1,2}, {3,4}}; const Param PART_ONE_2[] __attribute__((section("test_data_one"))) = {{7,8}}; // GCC自动生成段的起始和结束标记 extern Param __start_test_data_one; extern Param __stop_test_data_one; // 拼接后的数组范围:__start_test_data_one 到 __stop_test_data_one // 数组大小计算:(&__stop_test_data_one - &__start_test_data_one)
内容的提问来源于stack exchange,提问作者tteng little
相关产品推荐
相关产品推荐

