extern void myprint(unsigned char *);
static inline void
myfunc(unsigned char *buf)
{
for (unsigned int i = 0; i < 20; i++) {
buf[i] = i;
}
}
int
main(void)
{
unsigned char buf[10];
myfunc(buf);
myprint(buf);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
$ gcc.exe -O2 -pedantic -Wextra -Wall -Wstringop-overflow -Wuninitialized -Wunused -Warray-bounds=2 -Wformat-overflow -Wstringop-overread -g -c C:\temp\cb\main.c -o build\mingw\obj\main.o
$ gcc.exe -o build\mingw\test.exe build\mingw\obj\main.o build\mingw\obj\mod.o -O2
Run Code Online (Sandbox Code Playgroud)
$ gcc --version
gcc (i686-posix-sjlj-rev1, Built by MinGW-W64 project) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)
如果内联函数直接写在 main() 内部,gcc 会发出数组越界警告,但为什么它不能用静态内联函数检测到相同的警告呢?
我不太了解输出汇编器,但在我看来,生成的循环确实是 20 次,因此在执行过程中溢出是真实的。
编辑于 2023 年 12 月 1 日 09:13
阅读一些回复后,我尝试更改 myfunc() API,但使用 -O2 时,gcc 不会发出警告。
#include <stddef.h>
extern void myprint(unsigned char *);
static inline void
myfunc(unsigned char *buf, size_t size)
{
for (unsigned int i = 0; i < size + 1; i++) {
buf[i] = i;
}
}
int
main(void)
{
unsigned char buf[10];
myfunc(buf, 10);
myprint(buf);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
inline只是对编译器的建议(大部分已过时),它不强制内联。碰巧的是,您确实会在 下收到警告,-O3但不是在 下-O2。一些注意事项:
-O2/选项确实-O3会内联该函数(在 x86_64 gcc 13.3 上),但方式不同,其中一种方式-O3恰好是呈现诊断消息的方式。inline关键字不会改变生成的程序集,也不会改变内联的决定。__attribute__((always_inline))对您是否收到警告也没有影响。这里的最佳实践是不要依赖 gcc 发出此警告 - C 中的越界访问错误很少伴随着编译器警告。相反,您可以以类型安全的方式设计该函数:
static inline void myfunc(unsigned char buf[20])
Run Code Online (Sandbox Code Playgroud)
或者
static inline void myfunc(size_t size, unsigned char buf[size])
Run Code Online (Sandbox Code Playgroud)
或者如果采取极端的话(非常安全但API很麻烦):
static inline void myfunc(unsigned char (*buf)[20])
Run Code Online (Sandbox Code Playgroud)