关于GCC的__attribute__ ((constructor))

本文介绍了GCC编译器中的__attribute__((constructor))和__attribute__((destructor))属性的使用方法。通过示例代码展示了带有构造函数属性的函数会在main()函数前执行,而带有析构函数属性的函数则在main()退出时执行。
关于GCC的__attribute__ ((constructor))

    gcc为函数提供了几种类型的属性,其中包含:构造函数(constructors)和析构函数(destructors)。

程序员应当使用类似下面的方式来指定这些属性:

    static void start(void) __attribute__ ((constructor));
    static void stop(void) __attribute__ ((destructor));
带有"构造函数"属性的函数将在main()函数之前被执行,而声明为"析构函数"属性的函数则将在main()退出时执行。
    下面给出一个简单的程序作为例子:
  1. /* test.c */  
  2.   
  3. #include<stdio.h>  
  4. __attribute__((constructor)) void before_main()  
  5. {  
  6.    printf("before main/n");  
  7. }  
  8.   
  9. __attribute__((destructor)) void after_main()  
  10. {  
  11.    printf("after main/n");  
  12. }  
  13.   
  14. int main()  
  15. {  
  16.    printf("in main/n");  
  17.    return 0;  
  18. }  

$ gcc test.c -o test 
$ ./test 
before main 
in main 
after main

根据上面的代码以及输出结果,我们可以猜到__attribute__((constructor))表示这段代码将在main函数前调用,就像在C++里面的全局变量类的构造一样.

-- Performing Test HAVE_GCC_THREAD_LOCAL_STORAGE -- Performing Test HAVE_GCC_THREAD_LOCAL_STORAGE - Success -- Performing Test HAVE_MSC_THREAD_LOCAL_STORAGE -- Performing Test HAVE_MSC_THREAD_LOCAL_STORAGE - Failed -- Performing Test HAVE_CONSTRUCTOR_ATTRIBUTE -- Performing Test HAVE_CONSTRUCTOR_ATTRIBUTE - Failed -- Performing Test HAVE_DESTRUCTOR_ATTRIBUTE -- Performing Test HAVE_DESTRUCTOR_ATTRIBUTE - Failed -- Performing Test HAVE_FALLTHROUGH_ATTRIBUTE -- Performing Test HAVE_FALLTHROUGH_ATTRIBUTE - Failed -- Performing Test HAVE_GCC_VOLATILE_MEMORY_PROTECTION -- Performing Test HAVE_GCC_VOLATILE_MEMORY_PROTECTION - Failed -- Performing Test HAVE_GCC_NARG_MACRO -- Performing Test HAVE_GCC_NARG_MACRO - Failed -- Performing Test HAVE_COMPILER__FUNC__ -- Performing Test HAVE_COMPILER__FUNC__ - Failed -- Performing Test HAVE_COMPILER__FUNCTION__ -- Performing Test HAVE_COMPILER__FUNCTION__ - Failed -- Performing Test HAVE_GCC_BOUNDED_ATTRIBUTE -- Performing Test HAVE_GCC_BOUNDED_ATTRIBUTE - Failed -- Performing Test HAVE_LD_VERSION_SCRIPT -- Performing Test HAVE_LD_VERSION_SCRIPT - Failed -- Check if the system is big endian -- Searching 16 bit integer -- Looking for sys/types.h -- Looking for sys/types.h - not found -- Looking for stddef.h -- Looking for stddef.h - not found -- Check size of unsigned short -- Check size of unsigned short - failed -- Check size of unsigned int -- Check size of unsigned int - failed -- Check size of unsigned long -- Check size of unsigned long - failed CMake Error at /usr/share/cmake-3.5/Modules/TestBigEndian.cmake:51 (message): no suitable type found Call Stack (most recent call first): ConfigureChecks.cmake:417 (test_big_endian) CMakeLists.txt:98 (include) -- Configuring incomplete, errors occurred! See also "/home/bba/work/BBA1_5/MBB_Platform/apps/public/libssh/build/CMakeFiles/CMakeOutput.log". See also "/home/bba/work/BBA1_5/MBB_Platform/apps/public/libssh/build/CMakeFiles/CMakeError.log". make/apps/pubapps/libssh.mk:9: recipe for target 'libssh' failed make: *** [libssh] Error 1
最新发布
10-08
你遇到的 CMake 配置错误如下: ``` CMake Error at /usr/share/cmake-3.5/Modules/TestBigEndian.cmake:51 (message): no suitable type found Call Stack (most recent call first): ConfigureChecks.cmake:417 (test_big_endian) CMakeLists.txt:98 (include) ``` 同时,日志中显示: - 多个编译器特性测试失败(如 `HAVE_CONSTRUCTOR_ATTRIBUTE`、`HAVE_FALLTHROUGH_ATTRIBUTE` 等) - 关键系统头文件未找到:`sys/types.h`, `stddef.h` - 基本数据类型大小探测失败:`unsigned short`, `int`, `long` 等 --- ## 🔴 根本原因分析 这些错误表明 **CMake 无法执行最基本的系统探测**,说明你的构建环境缺少以下关键组件之一或多个: ### ❌ 问题根源总结: | 错误表现 | 可能原因 | |--------|---------| | `Looking for sys/types.h - not found` | 缺少标准 C 头文件(glibc 开发包) | | 所有 `Check size of ...` 失败 | C 编译器不能运行“测试程序” | | `no suitable type found` | CMake 的 `TestBigEndian.cmake` 模块依赖基本类型存在,但找不到任何整型 | | 所有 attribute 测试失败 | 编译器调用异常或交叉编译配置不当 | > ✅ 这通常发生在: > - **缺少 glibc 开发包** > - **使用了错误的交叉编译工具链** > - **工具链路径不完整或环境变量设置错误** > - **目标平台架构与编译器不匹配** --- ## ✅ 解决方案 ### ✅ 第一步:确认是否为交叉编译? 你是本地原生编译还是交叉编译? #### 判断方法: ```bash which gcc # 如果输出 /usr/bin/gcc → 原生编译 # 如果输出类似 /opt/toolchain/arm-linux-gnueabi/bin/gcc → 交叉编译 ``` --- ### ✅ 方案一:【适用于原生编译】安装缺失的开发头文件(Ubuntu/Debian) 如果你是在 Linux 主机上原生编译,但缺少 `sys/types.h`,说明没有安装标准 C 库开发包。 #### ✔️ 安装命令: ```bash sudo apt update sudo apt install build-essential libc6-dev ``` 或者更具体地: ```bash sudo apt install gcc g++ make cmake sudo apt install libc6-dev-amd64-cross # 或对应架构 ``` > 💡 特别注意:`sys/types.h` 属于 `glibc` 开发包(即 `libc6-dev`),必须安装! --- ### ✅ 方案二:【适用于交叉编译】正确配置工具链和 sysroot 如果你是 **交叉编译嵌入式设备(如 ARM)**,你需要提供一个完整的 **sysroot** 和正确的编译器前缀。 #### 示例目录结构(假设你的工具链已安装): ``` /opt/toolchain/ ├── bin/ │ ├── arm-linux-gnueabi-gcc │ └── ... ├── arm-linux-gnueabi/ │ ├── include/ │ │ ├── sys/types.h │ │ └── stddef.h │ └── lib/ ``` #### 创建 Toolchain 文件:`toolchain.cmake` ```cmake set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) # 工具链路径 set(TOOLCHAIN_PREFIX /opt/toolchain/arm-linux-gnueabi) # 编译器 set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}/bin/arm-linux-gnueabi-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}/bin/arm-linux-gnueabi-g++) # sysroot set(CMAKE_SYSROOT ${TOOLCHAIN_PREFIX}) # 搜索路径设置 set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) ``` #### 使用方式: ```bash cd build rm -rf * # 清除旧缓存 cmake .. \ -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake \ -DCMAKE_BUILD_TYPE=Release make ``` --- ### ✅ 方案三:检查并修复环境变量 有时即使工具链存在,环境问题也会导致检测失败。 #### 检查: ```bash arm-linux-gnueabi-gcc -E -x c /dev/null -o /dev/null && echo "OK" || echo "FAIL" ``` 如果报错(如 `command not found` 或 `cannot find crt1.o`),说明: - 工具链未加入 `PATH` - 或者 `sysroot` 不完整 #### 修复 PATH: ```bash export PATH=/opt/toolchain/arm-linux-gnueabi/bin:$PATH ``` 然后重新运行 CMake。 --- ### ✅ 方案四:手动指定基础类型(极端情况) 仅当所有自动探测都失败且你知道目标平台字节序时可用(不推荐)。 在 `CMakeCache.txt` 或通过 `-D` 参数强制定义: ```bash cmake .. \ -DHAVE_STDDEF_H=1 \ -DHAVE_SYS_TYPES_H=1 \ -DCMAKE_C_FLAGS="-I/opt/toolchain/arm-linux-gnueabi/include" \ -DTEST_BIG_ENDIAN=0 # 小端系统(ARM/Intel) ``` 但这只是绕过问题,不能治本。 --- ## ✅ 如何验证修复成功? 创建一个最简单的测试程序: ```c // test.c #include <sys/types.h> #include <stddef.h> #include <stdio.h> int main() { printf("size: %zu\n", sizeof(unsigned long)); return 0; } ``` 尝试编译: ```bash gcc test.c -o test # 原生 arm-linux-gnueabi-gcc test.c -o test # 交叉 ``` ✅ 成功 → 表示头文件和库路径正常 ❌ 失败 → 继续排查工具链或开发包 --- ## ✅ 总结 | 问题 | 原因 | 解决方法 | |------|------|----------| | `sys/types.h` 找不到 | 缺少 `libc6-dev` 或交叉编译无 sysroot | 安装开发包或配置 toolchain | | 类型大小探测失败 | 编译器无法运行测试程序 | 检查工具链路径和权限 | | `no suitable type found` | CMake 无法获取基本整数类型 | 必须修复头文件和编译器 | | attribute 测试失败 | 编译器调用失败或选项不支持 | 先解决基础问题再看这些 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值