Forum: Compiler & IDEs (pedantic) Warning ausschalten: ## __VA_ARGS__


von olpo (Gast)


Lesenswert?

Hallo,


mein aktuelles Projekt muss ich mit GCC -pedantic kompilieren.
Das wirft allerdings immer ERRORs bei meinem LOG macro.

1
#pragma GCC diagnostic push
2
#pragma GCC diagnostic warning "-Werror"
3
4
#define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
5
6
#pragma GCC diagnostic pop
1
app.c:123:45: error: ISO C99 requires rest arguments to be used [-Werror]
2
  LOG ("bla");


Ich habe versucht die Code-Stelle mit '#pragma GCC diagnostic' 
auszustellen, aber ohne Erfolg.
Ist vielleicht "-Werror" hier fehlplatziert?

Oder wie kann ich das hinbiegen, ohne das LOG macro zu ändern und 
-pendantic und -std=c99 eingeschaltet zu lassen?


Danke

von Dr. Sommer (Gast)


Lesenswert?

Erst -pedantic einschalten und dann jede Menge GCC-spezifische #pragma's 
verwenden? Klingt leicht sinnlos.

Dein Vorhaben funktioniert in Standard-C halt nicht. Entweder 
GCC-Erweiterungen erlauben, oder auf den Zeilenumbruch verzichten:
1
#define LOG printf
Oder Standard-C++ verwenden:
1
template <typename... Args>
2
inline void LOG (Args&&... args) {
3
  printf (std::forward<Args> (args)...);
4
  putc ('\n', stdout);
5
}
Aber da geht das alles auch schöner mit Streams.

von Kaj (Gast)


Lesenswert?

olpo schrieb:
> #define LOG (msg, ...)
             ^

Nimm mal das Leerzeichen weg...

von Kaj (Gast)


Lesenswert?

1
#include <stdio.h>
2
3
#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
4
5
int main(void)
6
{
7
    LOG("Hello World!");
8
    LOG("Hello World! %i", 56);
9
    return 0;
10
}
Compiliert bei mir total super.

von Dr. Sommer (Gast)


Lesenswert?

Kaj schrieb:
> Compiliert bei mir total super.

Dann versuch das mal mit "-pedantic" aktiviert, oder einem Compiler der 
nicht die GCC-Extensions hat, nämlich diese:

https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

Andere Compiler unterstützen das ", ## __VA_ARGS__" nicht 
notwendigerweise.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

olpo schrieb:
> Oder wie kann ich das hinbiegen, ohne das LOG macro zu ändern und
> -pendantic und -std=c99 eingeschaltet zu lassen?

Garnicht.  Du verwendest eine Spracherweiterung, willst aber striktes 
C99.  Entscheide dich mal!

http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

von Kaj (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Dann versuch das mal mit "-pedantic" aktiviert,
1
set( CMAKE_C_COMPILER "/usr/bin/gcc" )
2
set( CMAKE_C_FLAGS "-o -std=c99 -Wextra -Wall -pedantic -O0 -g3 -Wundef" )

Dr. Sommer schrieb:
> oder einem Compiler der
> nicht die GCC-Extensions hat
Warum? Hier ist expliziet vom GCC die rede...

Das einzige was bemängelt wird ist, wenn LOG() außer der Nachricht 
keinen weiteren parameter hat.
1
Warnung: ISO C99 requires at least one argument for the "..." in a variadic macro
2
     LOG("Hello World!");
3
                       ^

Das eigentliche Problem, das der TO hier hat, ist das er ein Leerzeichen 
zwischen LOG und den Klammern hat.

von g457 (Gast)


Lesenswert?

> Compiliert bei mir total super.

Dann hast Du die falschen Compileroptionen benutzt (oder den falschen 
Compiler).

So gehts:
1
$ cat test.c 
2
#include <stdio.h>
3
4
//#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
5
6
#define LOG2(msg, ...)  printf(msg "%s", __VA_ARGS__)
7
#define LOG(...)        LOG2(__VA_ARGS__, "\n")
8
9
10
int main(void)
11
{
12
    LOG("Hello World!");
13
    LOG("Hello World! %i", 56);
14
    return 0;
15
}
16
17
$ gcc -std=c99 -Wall -Wextra -pedantic -o test test.c
18
$ ./test 
19
Hello World!
20
Hello World! 56

..nicht nett, aber es geht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kaj schrieb:
> Das eigentliche Problem, das der TO hier hat, ist das er ein Leerzeichen
> zwischen LOG und den Klammern hat.

Nö.

von Dr. Sommer (Gast)


Lesenswert?

Kaj schrieb:
> Warum? Hier ist expliziet vom GCC die rede...
Naja, welchen Sinn hätte -pedantic wenn man nicht beabsichtigt, dass der 
Code auch auf andere Compiler portierbar sein soll? Und andere Compiler 
können das ", ## __VA_ARGS__" halt nicht.

Kaj schrieb:
> Das einzige was bemängelt wird ist, wenn LOG() außer der Nachricht
> keinen weiteren parameter hat.
Weil das auch eine GCC-Extension ist... Dass GCC die erste nicht 
anmeckert trotz -pedantic ist vermutlich ein Bug/Missing Feature.

g457 schrieb:
> ..nicht nett, aber es geht.
Ah, clever. Aber fies :)

von Kaj (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Naja, welchen Sinn hätte -pedantic wenn man nicht beabsichtigt, dass der
> Code auch auf andere Compiler portierbar sein soll?
Keine Ahnung, frag den TO :-)

g457 schrieb:
> Dann hast Du die falschen Compileroptionen benutzt (oder den falschen
> Compiler).
Nein.

Ohne das Leerzeichen:
1
$ gcc --version
2
gcc (GCC) 6.1.1 20160501
3
4
$ cat main.c
5
#include <stdio.h>
6
7
#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
8
9
int main(void)
10
{
11
    LOG("Hello World!");
12
    LOG("Hello World! %i", 56);
13
    return 0;
14
}
15
16
$ gcc -std=c99 -Wall -Wextra -pedantic -o main main.c
17
main.c: In Funktion »main«:
18
main.c:8:23: Warnung: ISO-C99 erfordert mindestens ein Argument für »...« in einem variadischen Makro
19
     LOG("Hello World!");
Das ist die einzige Warnung die kommt. Keine Errors!
Und die Warnung kommt auch nur ob des schlechten Beispiels.

Mit dem fehlerhaften Leerzeichen:
1
$ cat main.c
2
#include <stdio.h>
3
4
#define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
5
//         ^ Fehlerhaftes Leerzeichen!
6
7
int main(void)
8
{
9
    LOG("Hello World!");
10
    LOG("Hello World! %i", 56);
11
    return 0;
12
}
13
14
$ gcc -std=c99 -Wall -Wextra -pedantic -o main main.c
15
main.c:3:44: Warnung: __VA_ARGS__ kann nur in Erweiterung eines variadischen C99-Makros auftreten
16
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
17
                                            ^
18
main.c: In Funktion »main«:
19
main.c:3:14: Fehler: »msg« nicht deklariert (erste Benutzung in dieser Funktion)
20
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
21
              ^
22
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
23
     LOG("Hello World!");
24
     ^~~
25
main.c:3:14: Anmerkung: jeder nicht deklarierte Bezeichner wird nur einmal für jede Funktion, in der er vorkommt, gemeldet
26
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
27
              ^
28
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
29
     LOG("Hello World!");
30
     ^~~
31
main.c:3:19: Fehler: expected expression before »...« token
32
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
33
                   ^
34
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
35
     LOG("Hello World!");
36
     ^~~
37
main.c:3:17: Warnung: linker Operand des Komma-Ausdrucks hat keinen Effekt [-Wunused-value]
38
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
39
                 ^
40
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
41
     LOG("Hello World!");
42
     ^~~
43
main.c:3:25: Fehler: expected »;« before »printf«
44
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
45
                         ^
46
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
47
     LOG("Hello World!");
48
     ^~~
49
main.c:3:40: Fehler: das Einfügen von »,« und »__VA_ARGS__« ergibt kein gültiges Präprozessor-Token
50
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
51
                                        ^
52
main.c:7:5: Anmerkung: bei Substitution des Makros »LOG«
53
     LOG("Hello World!");
54
     ^~~
55
main.c:3:19: Fehler: expected expression before »...« token
56
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
57
                   ^
58
main.c:8:5: Anmerkung: bei Substitution des Makros »LOG«
59
     LOG("Hello World! %i", 56);
60
     ^~~
61
main.c:3:17: Warnung: linker Operand des Komma-Ausdrucks hat keinen Effekt [-Wunused-value]
62
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
63
                 ^
64
main.c:8:5: Anmerkung: bei Substitution des Makros »LOG«
65
     LOG("Hello World! %i", 56);
66
     ^~~
67
main.c:3:25: Fehler: expected »;« before »printf«
68
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
69
                         ^
70
main.c:8:5: Anmerkung: bei Substitution des Makros »LOG«
71
     LOG("Hello World! %i", 56);
72
     ^~~
73
main.c:3:40: Fehler: das Einfügen von »,« und »__VA_ARGS__« ergibt kein gültiges Präprozessor-Token
74
 #define LOG (msg, ...)  printf(msg "\n", ##__VA_ARGS__)
75
                                        ^
76
main.c:8:5: Anmerkung: bei Substitution des Makros »LOG«
77
     LOG("Hello World! %i", 56);

Johann L. schrieb:
> Nö.
Dann erklär mir doch bitte, warum mein GCC kein Error wirft, wenns doch 
angeblich nicht funktionieren dürfte...
Irgendwo scheinen Theorie und Praxis ja außeinander zu driften...

von olpo (Gast)


Lesenswert?

-Werror ist auch noch an.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Kaj schrieb:
> Johann L. schrieb:
>> Nö.
> Dann erklär mir doch bitte, warum mein GCC kein Error wirft, wenns doch
> angeblich nicht funktionieren dürfte...

Kann ich dir nicht sagen.
1
$ gcc-5.2.1 file.c -fsyntax-only -std=c99 -Wpedantic -Werror
1
#include <stdio.h>
2
3
#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
4
5
int main(void)
6
{
7
    LOG ("Hello World!");
8
    LOG ("Hello World! %i", 56);
9
    return 0;
10
}
1
file.c: In function 'main':
2
file.c:7:24: error: ISO C99 requires at least one argument for the "..." in a variadic macro [-Werror]
3
     LOG ("Hello World!");
4
                        ^
file.c:7:24: warning: ISO C99 requires at least one argument for the 
"..." in a variadic macro
     LOG ("Hello World!");

von g457 (Gast)


Lesenswert?

> Das ist die einzige Warnung die kommt.

Sehr schön, geht ja doch - um genau die Meldung gehts doch. Mach noch 
ein -Werror dazu und Du bekommst Deinen Fehler.

von Kaj (Gast)


Lesenswert?

g457 schrieb:
> Sehr schön, geht ja doch - um genau die Meldung gehts doch. Mach noch
> ein -Werror dazu und Du bekommst Deinen Fehler.
Hupsi, lesen und so... :-(

Ändert aber nichts daran, dass im eingangspost trotzdem das Leerzeichen 
falsch ist :P

Die Warnung leigt aber an der falschen benutzung des Makros.
Mach ein zweites Makro und alles ist schön.
1
#include <stdio.h>
2
3
#define LOG_WithoutArgs(msg)    printf(msg "\n")
4
#define LOG_WithArgs(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
5
6
int main(void)
7
{
8
    LOG_WithoutArgs("Hello World!");
9
    LOG_WithArgs("Hello World! %i", 42);
10
    return 0;
11
}

Der TO hat nicht einmal gezeigt wie er das Makor benutzt. Wenn er sein 
Makro richtig benutzt (mit zusätzlichen Argumenten!), gibt es beim 
compilieren auch keine warnung/fehler. ganz einfach.

olpo schrieb:
> Oder wie kann ich das hinbiegen, ohne das LOG macro zu ändern und
> -pendantic und -std=c99 eingeschaltet zu lassen?
Das Makro richtig benutzen.

Wenn du keine zusätzlichen Argumente hast, einfach einen Leerstring 
anhängen und alles ist schick und du kommst mit nur einem Makro aus und 
der Compiler hält die klappe.
Nicht das schönste, aber es könnte schlimmer sein.
1
$ cat main.c 
2
#include <stdio.h>
3
4
#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
5
6
int main(void)
7
{
8
    LOG("Hello World!%s", "");
9
    return 0;
10
}
11
$ gcc -std=c99 -Wall -Wextra -Werror -pedantic -o main main.c
12
13
$ ./main 
14
Hello World!

von olpo (Gast)


Lesenswert?

Danke soweit.

Eine Kompiler-unabhängige Lösung fuer '##__VA_ARGS__' gibt es ja nicht, 
oder?


Und weiß denn noch jemand, warum das Ausschalten des Warning nicht 
klappt?
1
#pragma GCC diagnostic push
2
#pragma GCC diagnostic warning "-Werror"
3
...
4
#pragma GCC diagnostic pop

von Rolf M. (rmagnus)


Lesenswert?

olpo schrieb:
> Eine Kompiler-unabhängige Lösung fuer '##__VA_ARGS__' gibt es ja nicht,
> oder?

Doch, allerdings erst seit 1999. Da es verbreitete Compiler gibt, die 
auf dem Stand von 1989 stehen geblieben sind, geht es trotzdem nicht mit 
jedem Compiler.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> olpo schrieb:
>> Eine Kompiler-unabhängige Lösung fuer '##__VA_ARGS__' gibt es ja nicht,
>> oder?
>
> Doch, allerdings erst seit 1999.

Mach mich schlau.  Das ist doch eine GCC-Erweiterung?

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Mach mich schlau.  Das ist doch eine GCC-Erweiterung?

Aus ISO C99:

"If the identifier-list in the macro definition does not end with an 
ellipsis, the number of arguments (including those arguments consisting 
of no preprocessing tokens) in an invocation of a function-like macro 
shall equal the number of parameters in the macro definition. Otherwise, 
there shall be more arguments in the invocation than there are 
parameters in the macro definition (excluding the ...). There shall 
exist preprocessing token that terminates the invocation.

The identifier __VA_ARGS__ shall occur only in the replacement-list of 
a function-like macro that uses the ellipsis notation in the arguments."

und

"An identifier __VA_ARGS__ that occurs in the replacement list shall 
be
treated as if it were a parameter, and the variable arguments shall form
the preprocessing tokens used to replace it."

Sowie:

Finally, to show the variable argument list macro facilities:
1
    #define debug(...)     fprintf(stderr, __VA_ARGS__)
2
    #define showlist(...)  puts(#__VA_ARGS__)
3
    #define report(test, ...) ((test)?puts(#test):\
4
                              printf(__VA_ARGS__))
5
6
    debug("Flag");
7
    debug("X = %d\n", x);
8
    showlist(The first, second, and third items.);
9
    report(x>y, "x is %d but y is %d", x, y);
results in
1
    fprintf(stderr, "Flag" );
2
    fprintf(stderr, "X = %d\n", x );
3
    puts( "The first, second, and third items." );
4
    ((x>y)?puts("x>y"):
5
          printf("x is %d but y is %d", x, y));

Man beachte, daß da kein ## vor dem __VA_ARGS__ steht.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> Johann L. schrieb:
>> Mach mich schlau.  Das ist doch eine GCC-Erweiterung?
>
> Aus ISO C99: [...]
> Finally, to show the variable argument list macro facilities:
>
1
#define debug(...)     fprintf(stderr, __VA_ARGS__)
> Man beachte, daß da kein ## vor dem __VA_ARGS__ steht.

Aber der Witz ist doch gerade das ## in Verbindung mit dem , vor dem ##: 
Falls __VA_ARGS__ nicht gegeben ist, entfernt der Präprozessor das 
Komma!

Aus "func(msg, ##__VA_ARGS__)" wird also "func(msg)" ohne das dann 
überflüssige ,

Wo siehst du so ein Feature im Standard?

von Rolf M. (rmagnus)


Lesenswert?

Johann L. schrieb:
> Aber der Witz ist doch gerade das ## in Verbindung mit dem , vor dem ##:
> Falls __VA_ARGS__ nicht gegeben ist, entfernt der Präprozessor das
> Komma!

Ok, dann habe ich die Frage missverstanden.
Das würde ich dann so lösen,w ie in 
Beitrag "Re: (pedantic) Warning ausschalten: ## __VA_ARGS__" beschrieben.

von olpo (Gast)


Lesenswert?

Na gut, dann ist das zur Zeit nur GCC spezifisch.

Aber noch mal zu meiner anderen Frage:

olpo schrieb:
> Und weiß denn noch jemand, warum das Ausschalten des Warning nicht
> klappt?
1
#pragma GCC diagnostic push
2
> #pragma GCC diagnostic warning "-Werror"
3
> ...
4
> #pragma GCC diagnostic pop

von Dr. Sommer (Gast)


Lesenswert?

olpo schrieb:
> Aber noch mal zu meiner anderen Frage:
>
> olpo schrieb:
>> Und weiß denn noch jemand, warum das Ausschalten des Warning nicht
>> klappt?
Weil die Warnung/Fehler erst bei der Nutzung des Makros auftritt, aber 
nicht bei der Definition, wo du dein #pragma aber dran geschrieben 
hast...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

olpo schrieb:
> Und weiß denn noch jemand, warum das Ausschalten des Warning nicht
> klappt?

Das ist eine Frage für die GCC Mailing-Liste gcc-help@gcc.gnu.org

Falls du dort nachfragst, bring bitte einen funktionierenden Testfall 
mit anstatt geschwärzten Code wie

>
1
#pragma GCC diagnostic push
2
> #pragma GCC diagnostic warning "-Werror"
3
> ...
4
> #pragma GCC diagnostic pop

Dort wird dir im Gegensatz zu hier nämlich niemand die Würmer aus der 
Nase ziehen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Einfach angewöhnen, dass das erste Argument von printf immer ein 
Format-String ist:
1
#include <stdio.h>
2
3
#define LOG(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
4
5
int main(void)
6
{
7
    LOG ("%s", "Hello World!");
8
    LOG ("%s %i", "Hello World!", 56);
9
    return 0;
10
}

Dann gibts auch keine Warnung.

Aus diesem Grund halte ich auch das erste C-Programm von K&R

   printf ("Hello, World\n");

für einen ziemlichen Missgriff. Didaktisch klüger wäre entweder ein

   puts ("Hello, World");

gewesen. Oder wenn es wirklich um printf() und die formatierte Ausgabe 
gegangen wäre, dann halt:

   printf ("%s", "Hello, World\n");

Meinetwegen auch noch eine Abart

   printf ("Hello %s\n", "World");

für Fortgeschrittene.

Aus diesem Grund benutze ich niemals printf & Co (sprintf, fprintf) ohne 
Format-String. Für solche Trivialfunktionen gibt es Alternativen wie 
z.B. puts() oder fputs().

Dem TO kann ich nur raten, zwei Macros anzulegen, nämlich LOG_PRINTF() 
und LOG_PUTS(). Dann ist klar, wann welches zu benutzen ist:
1
#include <stdio.h>
2
3
#define LOG_PRINTF(msg, ...)  printf(msg "\n", ##__VA_ARGS__)
4
#define LOG_PUTS(msg)         puts (msg)
5
6
int main(void)
7
{
8
    LOG_PUTS ("Hello World!");
9
    LOG_PRINTF ("%s %i", "Hello World!", 56);
10
    return 0;
11
}

: Bearbeitet durch Moderator
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.