overflow.h/Gcc5

本文介绍了一种使用编译器内置函数或通用方法来检测整数运算溢出的技术。对于支持的编译器如Clang和GCC,利用__builtin_add_overflow等内置函数可以直接进行溢出检查。对于不支持内置函数的编译器,则提供了通用实现方式。
#if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
/** assume clang and gcc (>=5) to only have builtins for now. */
#  define add_of(a, b, r) __builtin_add_overflow(a, b, r)
#  define sub_of(a, b, r) __builtin_sub_overflow(a, b, r)
#  define mul_of(a, b, r) __builtin_mul_overflow(a, b, r)
#  define of_attr
#else
/** else use these generics, note behaviour of these is not strictly defined. */
#  define add_of(a, b, r) ((*(r) = ((a) + (b))) < (a))
#  define sub_of(a, b, r) ((*(r) = ((a) - (b))) > (a))
#  define mul_of(a, b, r) (((*(r) = ((a) * (b))) || *(r) == 0) && ((a) != 0 && (b) > *(r) / (a)))
#  if __clang__
#     define of_attr __attribute__((optnone)) // Do not optimize above checks, in most systems this will work, but not defined.
#     warning "Using non compiler builtins for overflow checks, this will be undefined for signed integers"
#  elif __GNUC__
#     define of_attr __attribute__((optimize("wrapv"))) // in older GCC we can make this behavior defined
#  else
#     warning "Using non compiler builtins for overflow checks, this will be undefined for signed integers"
#  endif
#endif

aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_conn.o cpe_conn.c aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_epoll.o cpe_epoll.c In file included from cpe_epoll.c:1: /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/include/sys/errno.h:1:2: warning: #warning redirecting incorrect #include <sys/errno.h> to <errno.h> [-Wcpp] 1 | #warning redirecting incorrect #include <sys/errno.h> to <errno.h> | ^~~~~~~ aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_fw.o cpe_fw.c cpe_fw.c: In function 'CpeFwRule': cpe_fw.c:46:34: warning: '%d' directive writing between 1 and 3 bytes into a region of size 2 [-Wformat-overflow=] 46 | sprintf(Action, "%d", cpi->rule_table.rule[i].action); | ^~ cpe_fw.c:46:33: note: directive argument in the range [0, 255] 46 | sprintf(Action, "%d", cpi->rule_table.rule[i].action); | ^~~~ cpe_fw.c:46:17: note: 'sprintf' output between 2 and 4 bytes into a destination of size 2 46 | sprintf(Action, "%d", cpi->rule_table.rule[i].action); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_http.o cpe_http.c cpe_http.c: In function 'CpeParesHandle': cpe_http.c:61:13: warning: unused variable 'num' [-Wunused-variable] 61 | int num = strstr(mm->resp,"</Root>") - mm->resp; | ^~~ cpe_http.c: In function 'CpeUrlToken': cpe_http.c:287:42: warning: the comparison will always evaluate as 'false' for the address of 'passwd' will never be NULL [-Waddress] 287 | if(CpI->TokenInfo.passwd == NULL) | ^~ In file included from ../inc/cpe_http.h:6, from cpe_http.c:4: ../inc/cpe_main.h:112:14: note: 'passwd' declared here 112 | char passwd[17]; | ^~~~~~ aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_main.o cpe_main.c aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_sql.o cpe_sql.c aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_sql_recover.o cpe_sql_recover.c aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_timer.o cpe_timer.c aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_xml.o cpe_xml.c cpe_xml.c: In function 'Free_CpeRegisterInfo': cpe_xml.c:102:41: warning: the comparison will always evaluate as 'true' for the address of 'RegInfoTime' will never be NULL [-Waddress] 102 | if(CpeRegisterInfo->RegInfoTime != NULL){ | ^~ In file included from cpe_xml.c:16: ../inc/cpe_xml.h:55:14: note: 'RegInfoTime' declared here 55 | char RegInfoTime[11]; //注册时间 | ^~~~~~~~~~~ aarch64-openwrt-linux-gcc -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -c -o cpe_xml_dump.o cpe_xml_dump.c aarch64-openwrt-linux-gcc cpe_conn.o cpe_epoll.o cpe_fw.o cpe_http.o cpe_main.o cpe_sql.o cpe_sql_recover.o cpe_timer.o cpe_xml.o cpe_xml_dump.o -I ../inc -I/home/yzf/host/include/ -g -Wall -DARMFW -o xml -ldl -L../lib -lxml2 -lcurl -lnet_handle -lsqlite3 -lwhitelist_identifier /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_fw.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_http.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_main.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_sql.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_sql_recover.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_timer.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_xml.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/bin/../lib/gcc/aarch64-openwrt-linux-musl/12.3.0/../../../../aarch64-openwrt-linux-musl/bin/ld: cpe_xml_dump.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: multiple definition of `ls'; cpe_conn.o:/home/yzf/Nearlink/wgwl/xml_wg/src/../inc/cpe_log.h:16: first defined here collect2: error: ld returned 1 exit status make: *** [Makefile:29: xml] Error 1
08-13
<think>我们遇到了多个问题,主要集中在编译警告和链接错误。我将逐一分析并提供解决方案。 ### 问题1:多重定义错误(multiple definition of `ls') 这个错误发生在链接阶段,因为多个目标文件(cpe_conn.o, cpe_fw.o等)都定义了同一个全局变量`ls`。这通常是因为在头文件中定义了变量,然后被多个源文件包含,导致每个源文件都有一份定义。 #### 解决方案: 在头文件中使用`extern`声明变量,然后在**一个**源文件中定义该变量。 1. 修改头文件`cpe_log.h`: ```c // 将原来的定义改为extern声明 extern log_struct ls; ``` 2. 在某个源文件(比如`cpe_main.c`)中定义变量: ```c log_struct ls; ``` ### 问题2:编译警告 #### 2.1 头文件重定向警告 警告信息: ``` In file included from cpe_epoll.c:1: /home/yzf/toolchain-aarch64_generic_gcc-12.3.0_musl/include/sys/errno.h:1:2: warning: #warning redirecting incorrect #include <sys/errno.h> to <errno.h> [-Wcpp] 1 | #warning redirecting incorrect #include <sys/errno.h> to <errno.h> ``` **原因**:`#include <sys/errno.h>`是不正确的,应该使用`#include <errno.h>`。 **修改**:在`cpe_epoll.c`中,将`#include <sys/errno.h>`改为`#include <errno.h>`。 #### 2.2 格式溢出警告 警告信息: ``` cpe_fw.c:46:34: warning: '%d' directive writing between 1 and 3 bytes into a region of size 2 [-Wformat-overflow=] 46 | sprintf(Action, "%d", cpi->rule_table.rule[i].action); ``` **原因**:`Action`数组大小为2,但`%d`格式化一个整数(范围0-255)可能需要最多3个字符(如100)加上终止符'\0',共4个字符。 **修改**:将`Action`数组大小改为至少4,并使用`snprintf`防止溢出。 ```c char Action[4]; snprintf(Action, sizeof(Action), "%d", cpi->rule_table.rule[i].action); ``` #### 2.3 未使用变量 警告信息: ``` cpe_http.c:61:13: warning: unused variable 'num' [-Wunused-variable] 61 | int num = strstr(mm->resp,"</Root>") - mm->resp; ``` **原因**:变量`num`被声明但未被使用。 **修改**:删除这行代码。 #### 2.4 无效的地址比较(永远为假) 警告信息: ``` cpe_http.c:287:42: warning: the comparison will always evaluate as 'false' for the address of 'passwd' will never be NULL [-Waddress] 287 | if(CpI->TokenInfo.passwd == NULL) ``` **原因**:`passwd`是一个固定大小的数组,其地址永远不会为NULL。 **修改**:如果目的是检查字符串是否为空,应该检查第一个字符是否为'\0'。 ```c if (CpI->TokenInfo.passwd[0] == '\0') ``` #### 2.5 另一个无效的地址比较(永远为真) 警告信息: ``` cpe_xml.c:102:41: warning: the comparison will always evaluate as 'true' for the address of 'RegInfoTime' will never be NULL [-Waddress] 102 | if(CpeRegisterInfo->RegInfoTime != NULL){ ``` **原因**:`RegInfoTime`是一个固定大小的数组,其地址永远不会为NULL。 **修改**:同样,检查字符串内容是否为空。 ```c if (CpeRegisterInfo->RegInfoTime[0] != '\0') ``` ### 修改后的代码示例 #### 修改`cpe_log.h`(头文件) ```c // 修改前:log_struct ls; // 修改后: extern log_struct ls; ``` #### 在`cpe_main.c`中添加定义 ```c log_struct ls; // 全局变量的定义 ``` #### 修改`cpe_epoll.c`中的头文件包含 ```c // 修改前 #include <sys/errno.h> // 修改后 #include <errno.h> ``` #### 修改`cpe_fw.c`中的格式化代码 ```c // 修改前 char Action[2]; sprintf(Action, "%d", cpi->rule_table.rule[i].action); // 修改后 char Action[4]; snprintf(Action, sizeof(Action), "%d", cpi->rule_table.rule[i].action); ``` #### 修改`cpe_http.c`:删除未使用变量和修正条件 ```c // 删除未使用的变量num // 在函数CpeParesHandle中,删除行:int num = ...; // 修改条件判断 // 修改前 if(CpI->TokenInfo.passwd == NULL) // 修改后 if(CpI->TokenInfo.passwd[0] == '\0') ``` #### 修改`cpe_xml.c`中的条件 ```c // 修改前 if(CpeRegisterInfo->RegInfoTime != NULL) // 修改后 if(CpeRegisterInfo->RegInfoTime[0] != '\0') ``` ### 总结 通过以上修改,应该能够解决链接错误和编译警告。主要修改点包括: 1. 全局变量`ls`在头文件中改为`extern`声明,并在一个源文件中定义。 2. 修复了头文件包含问题。 3. 修复了缓冲区溢出风险。 4. 删除了未使用的变量。 5. 修正了无效的地址比较。 ### §§相关问题§§: 1. C语言中`extern`关键字的用法是什么? 2. 如何避免在头文件中定义变量? 3. 使用`snprintf`代替`sprintf`有什么好处? 4. 在C语言中,如何正确检查一个字符数组是否为空?</think>### 问题分析与解决方案 您遇到的编译问题主要包含两类: 1. **链接错误**:多个目标文件中重复定义了全局变量 `ls` 2. **编译警告**:包括格式溢出、未使用变量、无效指针检查等 --- ### 1. 解决链接错误(多重定义问题) **问题核心**:`cpe_log.h` 头文件中直接定义了全局变量 `ls`,导致每个包含该头文件的源文件都创建了自己的 `ls` 实例。 **解决方案**: 1. 修改头文件 `inc/cpe_log.h`: ```c // 修改前(错误示例): log_struct ls; // 直接定义 // 修改后(正确方式): extern log_struct ls; // 仅声明 ``` 2. 在任意**一个**源文件(如 `cpe_main.c`)中添加实际定义: ```c // 在 cpe_main.c 顶部添加 log_struct ls; // 实际定义 ``` **原理说明**: - `extern` 关键字声明变量存在于其他文件中 - 实际定义只能出现在一个源文件中 - 链接器在连接时会将所有对 `ls` 的引用指向单一实例 --- ### 2. 修复编译警告 #### (1) 格式溢出警告 (cpe_fw.c) ```c // 修改前(危险): char Action[2]; sprintf(Action, "%d", action_value); // 可能溢出 // 修改后(安全): char Action[4]; // 至少4字节(3位数字+1结束符) snprintf(Action, sizeof(Action), "%d", action_value); // 安全函数 ``` **说明**: - `int` 值最大可能为 32767(5字符),但此处值范围是 [0,255] - 使用 `snprintf` 防止缓冲区溢出 - 缓冲区大小从 2 增加到 4 确保安全 #### (2) 无效指针检查 (cpe_http.c) ```c // 修改前(无效检查): if(CpI->TokenInfo.passwd == NULL) // 数组地址永不为NULL // 修改后(检查空内容): if(CpI->TokenInfo.passwd[0] == '\0') // 检查空字符串 ``` **说明**: - 栈上数组的地址永远不会是 NULL - 检查第一个字符是否为结束符 `\0` 判断是否为空字符串 #### (3) 未使用变量 (cpe_http.c) 直接删除未使用的 `num` 变量: ```c // 删除此行: int num = strstr(mm->resp,"</Root>") - mm->resp; ``` #### (4) 无效指针检查 (cpe_xml.c) ```c // 修改前: if(CpeRegisterInfo->RegInfoTime != NULL) // 修改后: if(CpeRegisterInfo->RegInfoTime[0] != '\0') // 检查内容是否为空 ``` #### (5) 头文件重定向警告 (cpe_epoll.c) 修改包含方式: ```c // 修改前: #include <sys/errno.h> // 修改后: #include <errno.h> // 标准头文件 ``` --- ### 完整修改示例 #### 文件:`inc/cpe_log.h` ```c // 修改后 extern log_struct ls; // 仅声明不定义 ``` #### 文件:`src/cpe_main.c` ```c // 添加在全局区域 log_struct ls; // 实际定义 ``` #### 文件:`src/cpe_fw.c` ```diff // 在函数 CpeFwRule 中修改: - char Action[2]; + char Action[4]; - sprintf(Action, "%d", cpi->rule_table.rule[i].action); + snprintf(Action, sizeof(Action), "%d", cpi->rule_table.rule[i].action); ``` --- ### 总结 1. **全局变量处理**: - 使用 `extern` 在头文件中声明 - 在单个源文件中实际定义 - 避免多重定义链接错误 2. **缓冲区安全**: - 使用 `snprintf` 替代 `sprintf` - 确保缓冲区足够容纳格式化输出 3. **语义正确性**: - 检查数组内容而非地址 - 删除未使用变量减少干扰警告 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值