0

我刚搬到 gcc4.9 。现在,当我运行 make 来编译我的程序时,我注意到消息的详细程度大大增加了。特别是在警告中,我收到了更多我不需要的信息,主要是这样的消息:

myfile.c: In function 'myfunc':
myfile.c:4677:10: warning: passing argument 1 of 'sprintf' from incompatible pointer type
sprintf(str1,"file.txt");
          ^
In file included from /usr/include/features.h:374:0,
                 from /usr/include/stdio.h:27,
                 from myfile.c:28:
/usr/include/i386-linux-gnu/bits/stdio2.h:31:1: note: expected 'char * __restrict__' but argument is of type 'char **'
 __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
 ^

我的编译参数总是相同的“-g -O3”。我尝试了 -g0 和 -g1,但详细程度并没有降低。
所以想问一下,我如何设置 gcc 来抑制警告中所有那些过多的编译时消息,从“包含在文件中......”开始的所有内容以及之后的内容?
编辑:
我想我必须详细说明我想要实现的目标。
我想要警告,所以我不需要 -w 选项。
我很想看看:

myfile.c: In function 'myfunc':
myfile.c:4677:10: warning: passing argument 1 of 'sprintf' from incompatible pointer type
sprintf(str1,"file.txt");
          ^

不想看到:

In file included from /usr/include/features.h:374:0,
                 from /usr/include/stdio.h:27,
                 from myfile.c:28:
/usr/include/i386-linux-gnu/bits/stdio2.h:31:1: note: expected 'char * __restrict__' but argument is of type 'char **'
 __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))

我对在 a 中声明原始 sprintf 不感兴趣,由 b 调用(......谁实际上可能对此感兴趣......?!?)
以前的 gcc 版本没有这个问题,所以我最好的猜测, gcc4.9中必须有一些新选项来删除它(但我找不到它)
有人知道如何进一步删除从“包含在文件中......”开始的所有内容(在警告中)?
谢谢

4

2 回答 2

3

强烈建议您不要这样做,但如果您坚持: gcc -w禁止所有警告。这是您可以从谷歌搜索“gcc 抑制警告”中发现的。. .

也就是说,警告是有效的——您似乎在代码中做错了事。如果您想摆脱警告,为什么不修复代码?然后你有更好的代码并且没有警告。

于 2015-04-10T19:22:21.150 回答
2

What you suggest is a workaround, but I can still try it. Could you please write here that filter you talk about?

OK; I'd create a shell script to do the hard work. There are two ways to handle it. One is to call the script gcc-filter and then instead of running:

gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c

you would run:

gcc-filter gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c

Using make, you can achieve that by specifying CC="gcc-filter gcc" or equivalent.

The alternative is to run the script after redirecting output:

gcc -g -O3 -Wall -Wextra -Werror -I/where/ever -c source.c 2>&1 | gcc-filter

I'm going to assume the first technique.

gcc-filter.sh

"$@" 2>&1 |
sed '/^In file /,/^ *^/d' >&2

The first line runs gcc (or whatever command is specified by the arguments; it doesn't have to be gcc) with the arguments as specified on the command line. It redirects both standard output and standard error to a pipe (I'll come back to this), which goes to sed.

The sed line looks for the pattern In file at the start of a line, and deletes from there up to the first line that starts with a caret after optional spaces. The redirection sends the information that it passes through to standard error.

There are two prime defects with the script as it stands:

  1. It assumes that standard output and standard error can be merged (or, more succinctly, that gcc doesn't write much to standard output).
  2. It works off one pattern of error reporting. If there are other sequences that should be filtered, you will need to add to the sed script.

You can deal with the standard output vs standard error issue, but it is mildly mind blowing (maybe 'mind puffing').

(
"$@" 2>&1 1>&3 |
sed '/^In file /,/^ *^/d' >&2
) 3>&1

The sub-shell ( ... ) 3>&1 sends data written to file descriptor 3 so it goes to standard output.

Inside the sub-shell 2>&1 1>&3 | arranges for:

  1. Standard output to go to the pipe.
  2. Standard error to go where standard output is going (the pipe).
  3. Standard output to go to file descriptor 3 (without changing where standard error is going, the pipe).

The sed command therefore gets the standard error output from gcc as its standard input, filters it, and the >&2 sends its standard output to standard error.

The net result is that standard error is filtered while standard output is not. However, be aware that you can end up with different interleaving of output from the two streams as a result of the buffering going on.

One other problem: exit status. The exit status of the script as written is the exit status of the sed command, which will be 0 under most circumstances. If we need to relay the exit status from gcc, we have to work with the Bash set -o pipefail, I think. Or you can poke at the PIPESTATUS array; exit ${PIPESTATUS[0]} should exit with the same exit status that gcc exited with.

Demonstrating the code working on Linux

The system is running an Ubuntu 14.04 LTS derivative with GCC 4.9.2.

Test code b.c

(I'd used up x.c, y.c, z.c, and a.c on other programs.)

#include <stdio.h>

int main(void)
{
  char array[512];
  char *buffer = array;

  sprintf(&buffer, "file.txt");
  printf("%s\n", buffer);
  return 0;
}

Compilation without gcc-filter.sh:

$ make b.o WFLAG3= WFLAG4= WFLAG5= WFLAG6= IFLAGS= LDFLAGS= LDLIBS= cc  -g  -O3 -std=c11 -Wall -Wextra     -Werror    -c -o b.o b.c
b.c: In function ‘main’:
b.c:8:3: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
   sprintf(&buffer, "file.txt");
   ^
In file included from /usr/include/features.h:374:0,
                 from /usr/include/stdio.h:27,
                 from b.c:1:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:31:1: note: expected ‘char * restrict’ but argument is of type ‘char **’
 __NTH (sprintf (char *__restrict __s, const char *__restrict __fmt, ...))
 ^
cc1: all warnings being treated as errors
<builtin>: recipe for target 'b.o' failed
make: *** [b.o] Error 1
$

Compilation with gcc-filter.sh

$ make b.o CC="./gcc-filter.sh gcc" 
./gcc-filter.sh gcc -g -O3 -std=c11 -Wall -Wextra -Werror -c -o b.o b.c
b.c: In function ‘main’:
b.c:8:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
   sprintf(&buffer, "file.txt");
           ^
cc1: all warnings being treated as errors
<builtin>: recipe for target 'b.o' failed
make: *** [b.o] Error 1
$

gcc-filter.sh

#!/bin/bash

set -o pipefail
(
"$@" 2>&1 1>&3 |
sed '/^In file /,/^ *^/d' >&2
) 3>&1

exit ${PIPESTATUS[0]}

And another test

I also created c.c which contained three sprintf() lines and three printf() lines, and the filtered output was:

$ ./gcc-filter.sh gcc -g -O3 -std=c11 -Wall -Wextra -Werror -c c.c
c.c: In function ‘main’:
c.c:8:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
   sprintf(&buffer, "file1.txt");
           ^
c.c:10:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
   sprintf(&buffer, "file2.txt");
           ^
c.c:12:11: error: passing argument 1 of ‘sprintf’ from incompatible pointer type [-Werror]
   sprintf(&buffer, "file3.txt");
           ^
cc1: all warnings being treated as errors
$

So multiple errors are handled properly (but in times past, more than one similar script has appeared to work on a single instance of an error message but when tested on multiple error messages, it was too enthusiastic about discarding output).

于 2015-04-10T21:55:43.820 回答