c++ complains about __VA_ARGS__ - c++

The following code has been compiled with gcc-5.4.0 with no issues:
% gcc -W -Wall a.c
...
#include <stdio.h>
#include <stdarg.h>
static int debug_flag;
static void debug(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
#define DEBUG(...) \
do { \
if (debug_flag) { \
debug("DEBUG:"__VA_ARGS__); \
} \
} while(0)
int main(void)
{
int dummy = 10;
debug_flag = 1;
DEBUG("debug msg dummy=%d\n", dummy);
return 0;
}
However compiling this with g++ has interesting effects:
% g++ -W -Wall -std=c++11 a.c
a.c: In function ‘int main()’:
a.c:18:10: error: unable to find string literal operator ‘operator""__VA_ARGS__’ with ‘const char [8]’, ‘long unsigned int’ arguments
debug("DEBUG: "__VA_ARGS__); \
% g++ -W -Wall -std=c++0x
<same error>
% g++ -W -Wall -std=c++03
<no errors>
Changing debug("DEBUG:"__VA_ARGS__); to debug("DEBUG:" __VA_ARGS__); i.e. space before __VA_ARGS__ enables to compile with all three -std= options.
What is the reason for such behaviour? Thanks.

Since C++11 there is support for user-defined literals, which are literals, including string literals, immediately (without whitespace) followed by an identifier. A user-defined literal is considered a single preprocessor token. See https://en.cppreference.com/w/cpp/language/user_literal for details on their purpose.
Therefore "DEBUG:"__VA_ARGS__ is a single preprocessor token and it has no special meaning in a macro definition. The correct behavior is to simply place it unchanged into the macro expansion, where it then fails to compile as no user-defined literal operator for a __VA_ARG__ suffix was declared.
So GCC is correct to reject it as C++11 code.
This is one of the backwards-incompatible changes between C++03 and C++11 listed in the appendix of the C++11 standard draft N3337: https://timsong-cpp.github.io/cppwp/n3337/diff.cpp03.lex
Before C++11 the string literal (up to the closing ") would be its own preprocessor token and the following identifier a second preprocessor token, even without whitespace between them.
So GCC is also correct to accept it in C++03 mode. (-std=c++0x is the same as -std=c++11, C++0x was the placeholder name for C++11 when it was still in drafting)
It is also an incompatibility with C (in all revisions up to now) since C doesn't support user-defined literals either and considers the two parts of "DEBUG:"__VA_ARGS__ as two preprocessor tokens as well.
Therefore it is correct for GCC to accept it as C code as well (which is how the gcc command interprets .c files in contrast to g++ which treats them as C++).
To fix this add a whitespace between "DEBUG:" and __VA_ARGS__ as you suggested. That should make it compatible with all C and C++ revisions.

Related

C99 designator member outside of aggregate initializer

struct Foo {
char a[10];
int b;
};
static Foo foo = {.a="bla"};
Compiling the above code gives the following gcc error:
$ gcc -std=gnu++2a test.cpp
C99 designator ‘a’ outside aggregate initializer
I thought that c-string designators in initializer list like these are ok in C++20? What am I missing? I am using gcc version 10.
This is a known bug with GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55227
Unfortunately, you will have to either not use designated initializers or use a different initializer for the array:
static Foo foo = {"bla"};
static Foo foo = {.a={'b', 'l', 'a', 0}};
I got the same error and I dealt with mv my.cpp my.c
You also can find answer in this link:
https://pcbartists.com/firmware/esp32-firmware/designator-outside-aggregate-initializer-solved/
#ifdef __cplusplus
extern "C"
{
#endif
// C code goes here
#ifdef __cplusplus
}
#endif
I use strncpy (from <cstring>), for example:
strncpy(foo.str, "hello", sizeof(foo_t::str));
It seems to be optimized away, therefore generating the same assembly as normal approach in newer GCC (11.3^) and the same as using Artyer solution (the accepted one) of using char array.
Godbolt link: https://godbolt.org/z/9G7b6PT9b
However, the solution might cause warning: missing initializer for member 'foo_t::str' [-Wmissing-field-initializers] if you have the -Wextra warnings enable, but you can use -Wno-missing-field-initializers to exclude it.
By the way, with stucts like that you always have to remember the space is limited, and in many cases you might want leave trailing zero for string end. Using strncpy you can force that by adding:
foo.str[sizeof(foo_t::str) - 1] = 0;

Why does GCC claim I'm violating "at least one argument for variadic macro" when I have at least one argument?

Here is the example code I used to reproduce this error:
#include <iostream>
#define TEST_2_ARG_MACRO_OVERLOAD(_1,_2,FUNC_NAME,...) FUNC_NAME
#define TEST_HELLO_IMPL(condition) do{ \
if(!(condition)) {\
std::cout << "hello!" << std::endl; \
}\
} while(0)
#define TEST_HELLO_MESSAGE_IMPL(condition, message) do{ \
if(!(condition)) {\
std::cout << "hello" << message << std::endl; \
}\
} while(0)
//Runs during runtime and debug
#define TEST_HELLO(...) TEST_2_ARG_MACRO_OVERLOAD(__VA_ARGS__, TEST_HELLO_MESSAGE_IMPL, TEST_HELLO_IMPL)(__VA_ARGS__)
int main()
{
auto x = 3 * (3);
TEST_HELLO(x >= 3);
}
In godbolt with GCC x86-64 8.2 using:
-std=c++14 -Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wpedantic -Werror
as arguments I get the following error:
<source>:24:22: error: ISO C++11 requires at least one argument for the "..." in a variadic macro [-Werror]
TEST_HELLO(x >= 3);
^
cc1plus: all warnings being treated as errors
Compiler returned: 1
Yet there is clearly at least one argument in the macro. Now I know this compiles when I don't enable this warning, and when I don't enable this warning as an error, but for other reasons I want to keep these compiler flags (or at least keep the same results).
Why does GCC claim that I've passed zero arguments when I have not?
The problem is actually with TEST_2_ARG_MACRO_OVERLOAD, the error message is slightly misleading.
The macro takes 3 arguments and ... , in ISO C++ that means you must pass at least 4 arguments but in fact you only pass 3. (Ref: C++17 [cpp.replace]/4)
The TEST_HELLO expands to TEST_2_ARG_MACRO_OVERLOAD(x >= 3, TEST_HELLO_MESSAGE_IMPL, TEST_HELLO_IMPL)(x >= 3) .

C++ Compile Error: gnu_printf is an unrecognized format function type

When compiling I am getting the same warning on 3 different lines of code in a .h file such as this:
warning gnu_printf is an unrecognized format function type
My flags look like this:
CFLAGS += -Wall -Wextra -Wformat -Wno-ignored-qualifiers -Wformat-security -Wno-unused-parameter \
Examples of the three lines of code producing this error below:
int ATTR_WARN_PRINTF(1,2) OutputDebugStringF(const char* pszFormat, ...);
std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...);
bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...);
I have many other uses of printf() in this file that are not producing any errors. I am a bit confused on the error in the formatting.
Apparently the failing code is:
#ifdef __GNUC__
#define ATTR_WARN_PRINTF(X,Y) __attribute__((format(gnu_printf,X,Y)))
#else
#define ATTR_WARN_PRINTF(X,Y)
#endif
int ATTR_WARN_PRINTF(1,2) OutputDebugStringF(const char* pszFormat, ...);
std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...);
bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...);
It seems that this works on any gcc between versions 4.4.7 and gcc trunk (9.0.0).
GCC 4.1.2 fails with:
<source>:7: warning: 'gnu_printf' is an unrecognized format function type
Also, clang always fails on this:
<source>:7:5: warning: 'format' attribute argument not supported: gnu_printf [-Wignored-attributes]
But from the original question it seems that the issue with a GCC which is too old. To fix this, check GCC version number:
#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
# define ATTR_WARN_PRINTF(X,Y) __attribute__((format(gnu_printf,X,Y)))
#elif defined(__GNUC__)
# define ATTR_WARN_PRINTF(X,Y) __attribute__((format(printf,X,Y)))
#else
# define ATTR_WARN_PRINTF(X,Y)
#endif
Maybe even it is better to restrict the format to printf instead of gnu_printf, and so the above condition can be simplified.
EDIT: As can be found on GCC history, the gnu_printf format was added in gcc-4.4.0
commit r133365. From what I understand, it is merely an alias to printf, and the gnu prefix was added to allow differentiation between printf of different compilers, such as possibly ms_printf.

Clang: error: invalid use of non-static data member

Is this gcc being overly nice and doing what the dev thinks it will do or is clang being overly fussy about something. Am I missing some subtle rule in the standard where clang is actually correct in complaining about this
Or should I use the second bit of code which is basically the how offsetof works
[adrian#localhost ~]$ g++ -Wall -pedantic -ansi a.cc
[adrian#localhost ~]$ a.out
50
[adrian#localhost ~]$ cat a.cc
#include <iostream>
struct Foo
{
char name[50];
};
int main(int argc, char *argv[])
{
std::cout << sizeof(Foo::name) << std::endl;
return 0;
}
[adrian#localhost ~]$ clang++ a.cc
a.cc:10:29: error: invalid use of non-static data member 'name'
std::cout << sizeof(Foo::name) << std::endl;
~~~~~^~~~
1 error generated.
[adrian#localhost ~]$ g++ -Wall -pedantic -ansi b.cc
[adrian#localhost ~]$ a.out
50
[adrian#localhost ~]$ cat b.cc
#include <iostream>
struct Foo
{
char name[50];
};
int main(int argc, char *argv[])
{
std::cout << sizeof(static_cast<Foo*>(0)->name) << std::endl;
return 0;
}
[adrian#localhost ~]$ clang++ b.cc
[adrian#localhost ~]$ a.out
50
I found adding -std=c++11 stops it complaining. GCC is fine
with it in either version.
Modern GCC versions allow this even in -std=c++98 mode. However, older versions, like GCC 3.3.6 of mine, do complain and refuse to compile.
So now I wonder which part of C++98 I am violating with this code.
Wikipedia explicitly states that such a feature was added in C++11, and refers to N2253, which says that the syntax was not considered invalid by the C++98 standard initially, but then intentionally clarified to disallow this (I have no idea how non-static member fields are any different from other variables with regard to their data type). Some time later they decided to make this syntax valid, but not until C++11.
The very same document mentions an ugly workaround, which can also be seen throughout the web:
sizeof(((Class*) 0)->Field)
It looks like simply using 0, NULL or nullptr may trigger compiler warnings for possible dereference of a null pointer (despite the fact that sizeof never evaluates its argument), so an arbitrary non-zero value might be used instead, although it will look like a counter-intuitive “magic constant”. Therefore, in my C++ graceful degradation layer I use:
#if __cplusplus >= 201103L
#define CXX_MODERN 2011
#else
#define CXX_LEGACY 1998
#endif
#ifdef CXX_MODERN
#define CXX_FEATURE_SIZEOF_NONSTATIC
#define CxxSizeOf(TYPE, FIELD) (sizeof TYPE::FIELD)
#else
// Use of `nullptr` may trigger warnings.
#define CxxSizeOf(TYPE, FIELD) (sizeof (reinterpret_cast<const TYPE*>(1234)->FIELD))
#endif
Usage examples:
// On block level:
class SomeHeader {
public:
uint16_t Flags;
static CxxConstExpr size_t FixedSize =
#ifdef CXX_FEATURE_SIZEOF_NONSTATIC
(sizeof Flags)
#else
sizeof(uint16_t)
#endif
;
}; // end class SomeHeader
// Inside a function:
void Foo(void) {
size_t nSize = CxxSizeOf(SomeHeader, Flags);
} // end function Foo(void)
By the way, note the syntax difference for sizeof(Type) and sizeof Expression, as they are formally not the same, even if sizeof(Expression) works — as long as sizeof (Expression) is valid. So, the most correct and portable form would be sizeof(decltype(Expression)), but unfortunately it was made available only in C++11; some compliers have provided typeof(Expression) for a long time, but this never was a standard extension.

Why is clang parsing this as a user-defined literal?

I have some code I am maintaining that I've started compiling under clang 3.3.
When compiling with "-std=c++11", clang generates an error (given below). I've distilled the offending code to the following:
#include <stdio.h>
#define DBG_PRT(__format, ...) \
printf("%s:%d:%s: "__format, __FILE__, \
__LINE__, __FUNCTION__, ## __VA_ARGS__)
int main()
{
DBG_PRT("%s\n", "Hi");
}
This is clang's output:
test.cpp:10:5: error: no matching literal operator for call to
'operator "" __format' with arguments of types 'const char *' and
'unsigned int'
DBG_PRT("%s\n", "Hi");
^ test.cpp:4:29: note: expanded from macro 'DBG_PRT'
printf("%s:%d:%s: "__format, __FILE__, \
^ 1 error generated.
Without spaces between the string literal and "__format", it doesn't seem like the preprocessor should be able to expand __format. It clearly is, though, when not specifying -std=c++11. G++ 4.4.7 (with and without -std=c++0x) compiles just fine.
Is there an error with the compiler?
This is because ""_ is a syntax for user-defined string literals. Put a space in between to have the old behavior (concatenate literals). GCC works fine because 4.4.7 does not implement user defined literals (it appeared in version 4.7).
Also, as #Fred have pointed out, try to avoid using reserved identifier (double underscore).