VARIADIC MACRO compile error - c++

I want to learn how to use macro.
I simply write a sample but failed to compile on my local g++4.9
#define P(...) printf("13", ##__VA_ARGS__)
int main() {
// your code goes here
P();
return 0;
}
I will get compile error as below
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:4:42: error: expected primary-expression before ')' token
#define P(...) printf("13", ##__VA_ARGS__)
^
main.cpp:7:5: note: in expansion of macro 'P'
P();
^
But the same code can be compiled on ideone....
http://ideone.com/ucEXXz
and also by VS2015.
Is there any reasonable explanation for this?
How can I write a portable macro for all compiler....
Thanks.

In C, functions that take variable arguments require a prototype declaration, while in C++, all functions require a prototype. The declaration for printf can be found in stdio.h.
#include <stdio.h>
#define P(...) printf("13", ##__VA_ARGS__)
int main() {
P();
return 0;
}
The ##__VA_ARGS__ syntax is non-standard. It is a "swallow comma if the __VA_ARGS__ is empty" extension implemented by GCC, and seems to have been adopted by other compilers.
Regarding the behavior of -std=c++14:
The compiler can accept several base standards, such as ‘c90’ or ‘c++98’, and GNU dialects of those standards, such as ‘gnu90’ or ‘gnu++98’. When a base standard is specified, the compiler accepts all programs following that standard plus those using GNU extensions that do not contradict it. For example, -std=c90 turns off certain features of GCC that are incompatible with ISO C90, such as the asm and typeof keywords, but not other GNU extensions that do not have a meaning in ISO C90, such as omitting the middle term of a ?: expression.
GCC documentation for -std=
The ##__VA_ARGS__ extension does not conflict with the standard. What is causing it to be rejected by the coliru site is that the -pedantic flag is set.
Valid ISO C and ISO C++ programs should compile properly with or without this option (though a rare few require -ansi or a -std option specifying the required version of ISO C). However, without this option, certain GNU extensions and traditional C and C++ features are supported as well. With this option, they are rejected.
GCC documentation for -pedantic

Related

Error "sigemptyset was not declared in this scope" when using C+11 and Newlib

We are catching compiler errors when using sigemptyset on Cygwin under Newlib. The error occurs with a C++ compiler, but only when -std=XXX is used. Without a standard option, the test program compiles and executes as expected.
The test program is below, and the Cygwin header of interest follows. I don't see anything suspicious in the Cygwin header.
I've tried tricks like #define _GNU_SOURCE and #define _XOPEN_SOURCE 700. I've also tried tricks like using the global and std namespaces. Related, see What does -D_XOPEN_SOURCE do/mean? and Namespace issues in c++11?.
What is causing the compile failure and how do I fix it?
$ cat ~/test.cxx
#include <signal.h>
int main(int argc, char* argv[])
{
struct sigaction new_handler;
return sigemptyset(&new_handler.sa_mask);
}
Without a -std=XXX, it results in:
$ g++ -c test.cxx
$
With a -std=XXX, it results in:
$ g++ -std=c++03 -c test.cxx
test.cxx: In function int main(int, char**):
test.cxx:6:44: error: sigemptyset was not declared in this scope
return sigemptyset(&new_handler.sa_mask);
And when trying to use sigemptyset in the global namespace:
$ g++ -std=c++03 -c test.cxx
test.cxx: In function ‘int main(int, char**)’:
test.cxx:6:12: error: ‘::sigemptyset’ has not been declared
return ::sigemptyset(&new_handler.sa_mask);
^
Things get worse when using -std=gnu++03 and friends.
The function is an extension over the ISO C standard.
http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigemptyset.html
as such is protected on /usr/include/sys/signal.h by
__XSI_VISIBLE >= 4
see /usr/include/sys/features.h for details.
As defaults the largest definition set is used, but -std=XXX reduces the definition scope
The issue was worked through at Botan 2.1.0 does not compile under Cygwin 2.8.0 with g++ 5.4.0. Here are the two comments of interest.
First, from noloader:
Cygwin uses Newlib, not GNU's libstdc++. When there's no
-std=c++XX, current GCC defaults to -std=gnu++11 (GCC 6 changes
to gnu++14 by default). I
believe GNU sources ensures expected functions, like sigaction, are
available.
You might consider trying -D_XOPEN_SOURCE=600 or
-D_XOPEN_SOURCE=700.
Also see C++ and feature guards Warning
Question on the
Newlib mailing list.
Second, from SideChannel:
Thanks to #noloader. Until now -std=c++11 was set in Makefile. The
important info is in above mentioned thread on the Newlib mailing
list. Yaakov Selkowitz wrote:
G++ defines _GNU_SOURCE on glibc targets, meaning that -std=c++NN is, contrary to the documentation, not strict ISO C++:
So, applying the patch #987
AND setting -std=gnu++11 works for me. I
did not try the other -D options (I think the other fact is more
fundamental). Summarizing, #randombit please apply the PR #987 and set
-std=gnu++11 for gcc under Cygwin.

How to deal with warnings about tail-padded arrays in C++?

I'm writing a C++ application which uses a C library that defines a tail-padded structure in one of its headers. Without going into too much details, it looks somewhat like this:
struct MyStruct {
// ... other members
// The last member, a tail-padding array
MyType myBuffer[];
}
I use -Wall -Wextra -Wpedantic -Werror with g++ and -std=c++0x.
Unfortunately, g++ gives me a warning about that array:
error: ISO C++ forbids zero-size array 'myBuffer' [-Wpedantic]
What is the right way to deal with this?
I know I can suppress the warning by adding a pragma to the header myself:
#pragma GCC diagnostic ignored "-Wpedantic"
But that doesn't feel right. What do you guys suggest?
You could
Remove the zero-sized array.
Build without -Wpedantic (possibly only for that file).
Build without -Werror and ignore the warning.
Build the code as C.

putchar_unlocked doesn't work in C++ 14 standard

I am using g++ (GCC) 4.9.3 on Cygwin. I am not able to use getchar_unlocked or putchar_unlocked with C++ 14 standard.
Consider this sample code
#include <cstdio>
int main() {
putchar_unlocked('1');
return 0;
}
When I compile and run with
g++ foo.cpp && a.exe && rm ./a.exe
I am getting expected output 1.
But when I do
g++ -std=c++14 foo.cpp && a.exe && rm ./a.exe
I am getting error saying putchar_unlocked was not declared.
foo.cpp: In function 'int main()':
foo.cpp:4:22: error: 'putchar_unlocked' was not declared in this scope
putchar_unlocked('1');
^
putchar_unlocked isn't part of any version of the C or C++ standards, and Cygwin doesn't implement any other standard that does provide putchar_unlocked.
Cygwin does provide putchar_unlocked as a non-standard extension, but you need to actually leave non-standard extensions enabled.
The default -std= version is -std=gnu++03 (or one of its synonyms). This is C++03 plus extensions. You changed it to -std=c++14. This is C++14 without extensions. Use -std=gnu++14 to leave extensions enabled.
putchar_unlocked is not part of any C++ standard. It is part of POSIX standard, but defining -std=c++14 causes gcc to define __STRICT_ANSI__ macro. Cygwin uses Newlib for C standard library, and from its sources we can see that this prevents putchar_unlocked from being declared, and also that there isn't any other macro to enable it anyway.
Therefore, we need to get rid of __STRICT_ANSI__. Using -std=gnu++14 should do that:
g++ -std=gnu++14 foo.cpp && a.exe && rm ./a.exe
A comment under the question points out that the code works with Ideone. This is probably, because Ideone runs on different platform (such as Linux), which probably has glibc, which provides putchar_unlocked with different conditions (from this manual page):
Feature Test Macro Requirements for glibc (see
feature_test_macros(7)):
getc_unlocked(), getchar_unlocked(), putc_unlocked(),
putchar_unlocked():
_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE || _BSD_SOURCE || _SVID_SOURCE

-std=c++ 98 and OS X 10.10

I'm currently trying to compiling my program with the -std=c++98 flag on OS X 10.10:
clang++ -std=c++98 -pedantic -W -Wall -Werror *.cpp
g++ -std=c++98 -pedantic -W -Wall -Werror *.cpp
Strangely when I compile with OS 10.10 no error are showed while some are showed with a GNU/Linux distribution.
With the GNU/Linux distribution I have some errors because I use s.open(file); instead of s.open(file.c_str()); but on OS X no error, even by using s.open(file);.
Maybe there is just a link between this error and the filesystem of each OS?
You're correct. This code shouldn't compile under C++98:
#include <fstream>
#include <string>
int main() {
std::string file("/tmp/foo.txt");
std::ifstream s;
s.open(file);
}
It's technically a bug in libc++, but it's one that I doubt that they will want to fix.
If you wanted, you could compile with libstdc++ as the standard library, which doesn't have this feature implemented (at least the version that apple distributes doesn't).
[10:13am][wlynch#watermelon /tmp] clang++ -std=c++98 -stdlib=libstdc++ foo.cc
foo.cc:7:12: error: no viable conversion from 'std::string' (aka 'basic_string<char>') to 'const char *'
s.open(file);
^~~~
/usr/include/c++/4.2.1/fstream:518:24: note: passing argument to parameter '__s' here
open(const char* __s, ios_base::openmode __mode = ios_base::in)
^
1 error generated.
The problem is that on OS X you're still using a C++11 implementation of the standard library, which includes such API changes as the ostream::open method accepting std::strings.
Changing the C++ standard with -std=c++98 does not affect the standard library being used, and libc++ does not implement C++98 (e.g., there's no #ifdef to remove those open(std::string) APIs when in C++98 mode) whereas I think libstdc++ does hide non-c++98 APIs when building in C++98 mode.

creal and cimag problems with Clang 3.4

I am compiling a library with Petsc using Clang 3.4 and get:
error: use of undeclared identifier 'creal'
it follows from the following define:
petscmath.h:121:38: note: expanded from macro 'PetscRealPartComplex'
#define PetscRealPartComplex(a) creal(a)
the only relevant info i can find is this, i don't know if this is something compiler-specific and some libraries are missing or i have some problems with Petsc.
I tried using `cimag()' as it is in a small test file, but i can't compile it with neither clang3.4 nor gcc4.8.
Anyone has any ideas what is happening. Google does not show any similar topics...
EDIT:
so here is a simple example:
#include <complex.h>
int main ()
{
double complex z;
double cc = cimag(z);
}
it does compile with Gcc4.8 (from macports): g++-mp-4.8 main.cc -o main
however in c11 mode it does not : g++-mp-4.8 -std=c++11 main.cc -o main:
expected initializer before 'z' double complex z;
clang does not compile it in either cases and produce the same error as above.
Reference: http://pubs.opengroup.org/onlinepubs/7999959899/basedefs/complex.h.html
The header shall define the following macros:
complex
Expands to _Complex.
Reference: http://en.cppreference.com/w/c/numeric/complex
If the macro constant STDC_NO_COMPLEX(C11) is defined by the
compiler, the header and all of the names listed here are
not provided.
Note that I get the same results when specifying -std=c++11 with GCC, but not -x c -std=c11. YMMV.