目录
在数组或结构体初始化时,编译器检测到初始化列表没有用大括号明确区分每个元素的初始化值,即初始化列表中的元素没有被正确地用大括号包围,导致编译器无法准确解析每个元素的初始值。 详见本文作者写的的其它文章:警告warning: missing braces around initializer [-Wmissing-braces]的解决办法-CSDN博客 https://wenchm.blog.csdn.net/article/details/146395354?spm=1011.2415.3001.5331。
同样地, 在数组或结构体初始化时,如果在初始化一个标量(如一个整数、浮点数或指针)时使用了花括号 {}
而不是单个值,编译器也会发出警告:“warning: braces around scalar initializer”。
一、警告
在 C 或 C++ 编程中,当你看到警告“warning: braces around scalar initializer”时,这通常意味着你在初始化一个标量(如一个整数、浮点数或指针)时使用了花括号 {}
而不是单个值。标量初始化应该使用单个值而不是花括号。
在 C99 和 C++11 标准中,对于数组和结构体,使用花括号初始化是推荐的做法,因为这可以更清晰地表达初始化内容。但对于标量(单个变量),这种用法是不必要的,并且可能导致混淆。标量应该直接使用单个值进行初始化。
1、错误的代码
int x = {5}; // 错误:标量不应该使用花括号
2、正确的代码
int x = 5; // 正确:使用单个值初始化标量
3、解决办法
确保在初始化标量时仅使用单个值,而不是花括号。如果代码中有类似 {...}
的初始化表达式,应该检查这些表达式是否真的需要花括号,或者是否应该简化为单个值。
比如:
int array[] = {1, 2, 3, 4}; // 正确:数组初始化可以使用花括号
int scalar = {5}; // 错误:标量不应该使用花括号
应该修改为:
int array[] = {1, 2, 3, 4}; // 正确:数组初始化
int scalar = 5; // 正确:标量初始化使用单个值
二、示例
以下是摘录一段与本文警告有关的应用程序,源程序比较复杂,在书写时曾遭遇本文提到的警告,先分享如下:
1、必要的定义
//本例中必要的结构体、联合体定义
//面板结构体类型定义
typedef struct{
STR_KEYSCAN KeyScan;
STR_PANELMENU Menu;
STR_LEDDISPLAY Display;
}STR_PANELOPERRATION;
//扫描按键结构体类型定义
typedef struct{
volatile UNI_SPIRXKEY_REG Input; //输入信号
volatile UNI_SPIRXKEY_REG FltrInput; //经滤波后的输入信号
ENU_KEYVAULE CurrKey; //当前键扫描的值
ENU_KEYEDGESTATUS KeyEdge; //当前键边沿状态
Uint8 ModeFltrCnt; //MODE键滤波计数器
Uint8 UpFltrCnt; //UP键滤波计数器
Uint8 DownFltrCnt; //DOWN键滤波计数器
Uint8 ShiftFltrCnt; /SHIFT键滤波计数器
Uint8 SetFltrCnt; //SET键滤波计数器
Uint8 AccCnt; //UP键和DOWN键加速计数器
Uint8 AccLevel; //UP键和DOWN键加速等级
Uint8 AccLevelCnt; //UP键和DOWN键加速等级计数器
}STR_KEYSCAN;
typedef union{
volatile Uint8 all;
volatile STR_SPIRXKEY_Bit bit;
}UNI_SPIRXKEY_REG;
// 键值定义
typedef enum{
MODEKEY = 0,
UPKEY = 1,
DOWNKEY = 2,
SHIFTKEY = 3,
LONG_SHIFTKEY = 4,
SETKEY = 5,
LONG_SETKEY = 6,
UPDOWNKEY = 7,
NONEKEY = 8,
}ENU_KEYVAULE;
//键状态定义
typedef enum{
INVALIDEDGE = 0,
VALIDEDGE = 1,
}ENU_KEYEDGESTATUS;
//面板菜单结构体类型定义
typedef struct{
volatile UNI_PANELMENUCTRL_REG CtrlReg; //面板菜单控制寄存器
int8 DispGroup; //显示功能码组
int8 DispOffset; //显示功能码组内偏移
Uint32 DispData; //LED数码管显示数据
Uint16 UserPass; //用户密码
}STR_PANELMENU;
typedef union{
volatile Uint16 all;
volatile STR_PANELMENUCTRL_BIT bit;
}UNI_PANELMENUCTRL_REG;
//面板菜单控制位定义
typedef struct{
Uint16 ErrShowSure:1; //故障确认标志位
Uint16 Class:4; //面板菜单等级
Uint16 Page:2; //面板菜单显示页数
Uint16 Class3rdMode:4; //面板第三级菜单显示模式
Uint16 DealBit:4; //面板正在操作的LED数码管位
Uint16 Class2ndDisp_SAVE:1; //第二级菜单显示SAVE标志位 0 不显示 1 显示
}STR_PANELMENUCTRL_BIT;
//LED显示结构体类型定义
typedef struct{
Uint8 DispData[5]; //LED数码管显示段数据
volatile UNI_LEDDISPLAYCTRL_REG CtrlReg; //控制寄存器
Uint8 Timer; //定时器,闪烁时使用
Uint8 TubeIndex; //当前显示的数码管序号
Uint8 TxTubeSel; //发送当前显示的数码管使能
Uint8 TxDispData; //发送当前显示的数码管数据
}STR_LEDDISPLAY;
typedef union{
volatile Uint8 all;
volatile STR_LEDDISPLAYCTRL_BIT bit;
}UNI_LEDDISPLAYCTRL_REG;
//LED显示控制寄存器定义
typedef struct{
Uint8 ZeroFlicker:1; //第0位数据闪烁控制位 0:不闪烁, 1:闪烁
Uint8 FirstFlicker:1; //第1位数据闪烁控制位 0:不闪烁, 1:闪烁
Uint8 SecondFlicker:1; //第2位数据闪烁控制位 0:不闪烁, 1:闪烁
Uint8 ThirdFlicker:1; //第3位数据闪烁控制位 0:不闪烁, 1:闪烁
Uint8 ForthFlicker:1; //第4位数据闪烁控制位 0:不闪烁, 1:闪烁
Uint8 DotFlicker:1; //小数点闪烁控制位 0:正常, 1:永远都不闪烁
Uint8 Rsvd:2; //保留
}STR_LEDDISPLAYCTRL_BIT;
2、错误的代码书写
宏定义PANELOPERRATION_DEFAULT的数据类型是STR_PANELOPERRATION结构体,并且结构体STR_PANELOPERRATION成员由另外的三个结构体构成。
//错误的代码书写,过多地使用了{}
#define PANELOPERRATION_DEFAULT \
{ \
{
{0xFF},{0xFF},{NONEKEY},{INVALIDEDGE},0,0,0,0,0,0,ACCLEVEL1ST,0}, \
{
{0},0,0,0,0}, \
{
{0xaf,0x86,0x92,0x86,0x87},{0},0,0,0,0}\
}
/* 变量定义 */
STR_PANELOPERRATION ServoPanel = PANELOPERRATION_DEFAULT;
3、正确的代码书写
//正确的代码书写,去除过多的{}
/*PANELOPERRATION_DEFAULT的构成 */
/*STR_KEYSCAN,12个成员,前2个成员是结构体,ENUM数值除外 */
/*STR_PANELMENU,5个成员。第1个成员是联合体*/
/*STR_LEDDISPLAY,6个成员,第1个成员是数组,第2个成员是联合体 */
#define PANELOPERRATION_DEFAULT \
{ \
{
{0xFF},{0xFF},NONEKEY,INVALIDEDGE,0,0,0,0,0,0,ACCLEVEL1ST,0}, \
{
{0},0,0,0,0}, \
{
{0xaf,0x86,0x92,0x86,0x87},{0},0,0,0,0}\
}
/* 变量定义 */
STR_PANELOPERRATION ServoPanel = PANELOPERRATION_DEFAULT;
总之,遇到“warning: braces around scalar initializer”这样的警告时,就是{}用错了地方。检查代码,确保标量的初始化是直接使用单个值而不是花括号。就可以避免不必要的编译器警告,并使代码更加清晰和符合标准。