奇怪的warning: “__have_long64” is not defined
引子
最近在使用一款nb模块的opencpu来做项目,遇到了个奇怪的问题。
可能有的同学没接触过opencpu,待我简单介绍下。opencpu是用来替代传统cpu的。传统的物联网项目,用的是单片机+通信模块。而通信模块里面也是有处理器的,并且其资源(cpu算力,ram和flash)往往富余。既然如此,就有厂家把通信模块的cpu资源开放出来,给用户跑业务程序。这样省去了两个cpu的通信,也省去了单片机的成本,省力又省钱。
我用的nb软硬件环境如下:
处理器:mips系列
编译器:mips-elf-4.4.2,gcc系列
厂家的SDK很少使用标准库,使用的基本数据类型都是自己定义的。
/****************************************************************************
* Type Definitions
***************************************************************************/
typedef unsigned char bool;
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef short s16;
typedef unsigned int u32;
typedef int s32;
typedef unsigned long long u64;
typedef long long s64;
typedef unsigned int ticks;
我不太喜欢这种做法,大家都是用C语言,标准库明明有现成的类型,为啥不去用呢。如果都用标准的定义,那会便于移植第三方代码。
问题
当然,SDK用自己的类型,不妨碍我用标准库嘛。当我引入<stdint.h>时,遇到了一个神奇的问题。编译时报如下warning,说__have_long64
和__int_fast64_t_defined
未定义。
E:\CSDTK4\/mips-elf-4.4.2/mips-elf/sys-include/stdint.h:114:5: warning: "__have_long64" is not defined
E:\CSDTK4\/mips-elf-4.4.2/mips-elf/sys-include/stdint.h:211:6: warning: "__int_fast64_t_defined" is not defined
E:\CSDTK4\/mips-elf-4.4.2/mips-elf/sys-include/stdint.h:311:5: warning: "__have_long64" is not defined
E:\CSDTK4\/mips-elf-4.4.2/mips-elf/sys-include/stdint.h:323:5: warning: "__have_long64" is not defined
先看看第一条warning指向的代码内容,即stdint.h文件114行。
stdint.h:144
#if __have_long64
typedef signed long int64_t;
typedef unsigned long uint64_t;
#define __int64_t_defined 1
#elif __have_longlong64
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#define __int64_t_defined 1
#elif __STDINT_EXP(INT_MAX) > 0x7fffffff
typedef signed int int64_t;
typedef unsigned int uint64_t;
#define __int64_t_defined 1
#endif
如上代码是根据一些宏来决定int64_t
和uint64_t
是真64位,还是32位(假64)。#if
命令在访问__have_long64
时该标识符不存在,从而引发了warning。那么该变量是在哪儿定义的呢,还是就没有定义呢。
这个opencpu只提供了makefile编译系统,木有IDE。虽然我用了TRUEStudio来编辑代码,不过无法在IDE中查看mips的标准库。让我们用强大的grep来查下,
Administrator@XOCQELJM3TW78G3 MINGW64 /e/CSDTK4/mips-elf-4.4.2/mips-elf/sys-include
$ grep -n --color -E "#define[[:space:]]+(\w+[[:space:]]+)*__have_long64" -R
stdint.h:35:#define __have_long64 1
这不是定义了吗,看看该处的代码。
stdint.h:33
/* Check if "long" is 64bit or 32bit wide */
#if __STDINT_EXP(LONG_MAX) > 0x7fffffff
#define __have_long64 1
#elif __STDINT_EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__)
#define __have_long32 1
#endif
看来其是否定义是由LONG_MAX
控制的。省去无聊的验证过程,最终确认:
定义了__have_long32
和__have_longlong64
,这样uint64_t是真的64位。确实没定义__have_long64
。
这些宏开关为非0值时,会包含相应的定义。比如__have_longlong64
用于定义真64位。
#elif __have_longlong64
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#define __int64_t_defined 1
解决
在不影响功能的情况下,想规避这个warning,我可以在头文件中添加:
#define __have_long64 0
加入后,__have_long64的warning是什么了,不过还有另一条。
I:\embedded\workspace\opencpu_nb_gas>make new
- Building build/gcc/obj/custom/main.o
In file included from common/_stddef.h:16,
from common/rtthread.h:16,
from utils/logger.h:6,
from custom/main.c:40:
E:\CSDTK4\/mips-elf-4.4.2/mips-elf/sys-include/stdint.h:212:6: warning: "__int_fast64_t_defined" is not defined
让我们再看看__int_fast64_t_defined吧。
推翻
等等,就这么把标准库的头文件给改了?这不大好吧,人家是标准库呢:)。
我们再来整理下问题:在#if命令中遇到了未定义的标识符,导致输出warning。
最简化模型为:
#if XXX
#endif
随手找个编译器试了下(TRUEStudio创建的PC平台工程):
没有报warning。而且,mips编译器也只是报了warning,还是可以编译运行的。__have_long64
被当成0来处理了。也就是说,这个warning可能是由编译参数来控制的,可以报警也可以不报警。毕竟,#if
把未定义的标识符当成0,这看起来也很合理。
让我们看下TRUEStudio编译用的命令,只有与Warning相关的是-Wall。
gcc -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu99 -o src\main.o ..\src\main.c
再看看NB SDK的编译命令,这个比较复杂,编译的部分参数如下:
CFLAGS=-std=gnu99 -mips16 -Wshadow -Os -g -msoft-float -Wundef -Wunused-function -Wuninitialized -minterlink-mips16 -nostdlib -nostdinc -nodefaultlibs -c \
-march=xcpu -mtune=xcpu -Wa,-march=xcpu,-mtune=xcpu \
-fno-inline-small-functions -fno-inline-functions -fno-align-functions -fno-align-jumps -fno-align-loops -fno-align-labels \
-pipe -fwide-exec-charset=UTF-16LE -fshort-wchar \
-fno-strict-aliasing -ffunction-sections -fdata-sections -fno-builtin-iswspace \
-ffixed-t3 -ffixed-t4 -ffixed-t5 -ffixed-t6 -ffixed-t7 -ffixed-s2 -ffixed-s3 -ffixed-s4 -ffixed-s5 -ffixed-s6 -ffixed-s7 -ffixed-fp -G0 -Wall \
-mexplicit-relocs -fweb -frename-registers -mmemcpy -mmips-tfile -nostartfiles \
-EL
再解决
万恶的-Wundef
藏匿其中,不过逃不过我火眼金睛。gcc手册中–Wall和-Wundef的部分说明如下:
- -Wall
This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid.
Note that some warning flags are not implied by ‘-Wall’. Some of them warn about constructions that users generally do not consider questionable, but which occasionally you might wish to check for; others warn about constructions that are necessary or hard to avoid in some cases, and there is no simple way to modify the code to suppress the warning. - -Wundef
Warn if an undefined identifier is evaluated in an #if directive. Such identifiers are replaced with zero.
-Wall
使能的warning有这么些特点:有些用户认为是可疑的(可能是bug),很容易规避。比如说,将int型变量赋值给指针。
int i = 0x08000000;
int *p = i;
当然,如果int型变量确实存的就是另一个变量的地址,那么规避这个warning也很简单。
int *p = (int *)i;
-Wall
的说明中也提到,其没有包含所有的warning。有些warning往往没有问题,不是潜在的bug。我觉得,-Wundef
就是这种类型的。
stdint.h:144
#if __have_long64
typedef signed long int64_t;
typedef unsigned long uint64_t;
#define __int64_t_defined 1
#elif __have_longlong64
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#define __int64_t_defined 1
#elif __STDINT_EXP(INT_MAX) > 0x7fffffff
typedef signed int int64_t;
typedef unsigned int uint64_t;
#define __int64_t_defined 1
#endif
再来回顾下这个__have_long64
,#if
在判断是否有long64时,其值为非0表示有。那么,定义一个值为0的__have_long64
和不定义是一样的效果,挺合理的嘛。而且,像TRUEStudio这种IDE创建的工程,其默认的warning参数也只有-Wall
,并没有-Wundef
。修改个工程配置总比修改标准库文件要靠谱。
总结
#if
遇到未定义的标识符时,会用0替换它。并且若编译参数加了-Wundef
,则会输出warning。-Wall
未包含-Wundef
,可能开发者认为-Wundef
不是一个可疑的warning,通常不需要关注。至于是否需要启用这条warning,就见仁见智了。
最后提一句:),NB SDK启用了-Wundef
,其实并不是他们的开发者多么严谨。这SDK包含了部分开源代码和一套示例。我编译时,有100+的warning。边改边骂,那些warning可真是that are easy to avoid。虽然那些warning没有一个是真正的bug,但是我若不改的话,当我自己开发时触发了可疑的warning时,我的warning将被淹没中100+warning的大海之中。当然,如果那样的话,我也不会看到这条“__have_long64” is not defined
。
转载请注明出处:https://blog.youkuaiyun.com/wenbodong/article/details/108387085
未经允许请勿用于商业用途。