vimer linux kernel 爱好者

gcc diagnostic用法

2021-07-04

目前中文的资料介绍diagnostic的介绍资料较少一些,故积累本文以作总结。

源码

Makefile 如下

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.c如下:

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while(*++argv)
        puts(*argv);
    return 0;
}

编译的时候,error显示如下:

vimer@user-HP:~/test/gcc$ make
cc  -std=c11 -W -Wall -pedantic -Werror   puts.c   -o puts
puts.c: In function ‘main’:
puts.c:12:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
 int main(int argc, const char *argv[])
              ^~~~
cc1: all warnings being treated as errors
<builtin>: recipe for target 'puts' failed
make: *** [puts] Error 1

之所以有这些error,需要注意到cppflags的那几个字段,是这几个决定了编译的具体行为。 当然,gcc编译的常用选项也需要进行一番总结。

改进

arrtibute

  1. attribute 可以使用这个关键字进行某些warning的消除。
    int main(__attribute__((unused)) int argc, const char *argv[])
    {
     while(*++argv)
         puts(*argv);
     return 0;
    }
    

    编译结果:

    vimer@user-HP:~/test/gcc$ make
    cc  -std=c11 -W -Wall -pedantic -Werror   puts.c   -o puts
    

__attribute__是GCC的扩展,当然也是来自LLVM的支持。如果想写出可移植的代码,需要将该字段放到宏中去编写。 这个后面我们再总结一下。

_Pragma

这个代码没有编译成功:

#include <unistd.h>

_Pragam("GCC diagnostic push")
_Pragam("GCC diagnostic ignore \"-Wunused-parameter\"")


int main(__attribute__((unused)) int argc, const char *argv[])
{
    while(*++argv)
        puts(*argv);
    return 0;
}
_Pragam("GCC diagnostic pop")

编译的log如下,但是这篇文章的主旨不是这里,所以暂且不表。

vimer@user-HP:~/test/gcc$ make
cc  -std=c11 -W -Wall -pedantic -Werror   puts.c   -o puts
puts.c:11:9: error: expected declaration specifiers or ‘...’ before string constant
 _Pragam("GCC diagnostic push")
         ^~~~~~~~~~~~~~~~~~~~~
puts.c:21:9: error: expected declaration specifiers or ‘...’ before string constant
 _Pragam("GCC diagnostic pop")
         ^~~~~~~~~~~~~~~~~~~~
<builtin>: recipe for target 'puts' failed
make: *** [puts] Error 1

#pragma

先看代码

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"


int main(__attribute__((unused)) int argc, const char *argv[])
{
    while(*++argv)
        puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

编译的log如下:

vimer@user-HP:~/test/gcc$ make
cc  -std=c11 -W -Wall -pedantic -Werror   puts.c   -o puts

怎么样,出乎意料吧,其实这里才是这篇文章的主题: c源码程序中借助这样的技巧,把一些不可避免的 warning给屏蔽掉。看一下我们的工程代码:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#include <gst/video/videooverlay.h>
#pragma GCC diagnostic pop

这里难道是 include 的文件有问题? -Wconversion大概率设涉及到类型的转换之类的。而且,这个声明必须放到 .c文件中去做。

Makefile

最后是修改Makefile,实际效果我没有进行试验,但是我估计应该是可以的。

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

具体的code 参考

pragma

这个用法是有具体语法的,比如

#pragma GCC diagnostic kind option

以下摘自官方:

Modifies the disposition of a diagnostic. Note that not all diagnostics are modifiable; at the moment only warnings (normally controlled by ‘-W…’) can be controlled, and not all of them. Use -fdiagnostics-show-option to determine which diagnostics are controllable and which option controls them.

kind is ‘error’ to treat this diagnostic as an error, ‘warning’ to treat it like a warning (even if -Werror is in effect), or ‘ignored’ if the diagnostic is to be ignored. option is a double quoted string that matches the command-line option.
#pragma GCC diagnostic warning "-Wformat"
#pragma GCC diagnostic error "-Wformat"
#pragma GCC diagnostic ignored "-Wformat"
Note that these pragmas override any command-line options. GCC keeps track of the location of each pragma, and issues diagnostics according to the state as of that point in the source file. Thus, pragmas occurring after a line do not affect diagnostics caused by that line.

说的很明白,就是 #pragma会覆盖编译选项的(比如来自makefile什么的),所以引入了下面的技巧:

#pragma GCC diagnostic push
#pragma GCC diagnostic pop

下一篇 gcc 选项解析

Comments

Content