Anyone knows why the following code works under g++ 4.7.2? If I change the name printf to another name such as f, it has compiler error saying constexpr can't contain non-const function calls (which I think is the correct behavior).
[hidden]$ cat d.cpp
extern "C" { extern int printf(const char* s, ...); }
constexpr int g() { return printf(""), 0; }
template <int N> struct X { const static int value = N; };
int n = X<g()>::value;
[hidden]$ g++ -std=c++11 -c d.cpp
[hidden]$ g++ -v |& tail -1
gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC)
Note I don't include any header files.
printf() is handled as a builtin function by GCC/g++ in many cases (though I think this behavior is still a bug). From http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html:
The ISO C90 functions ... printf ... are all recognized as built-in functions unless -fno-builtin is specified (or -fno-builtin-function is specified for an individual function)
You get the correct diagnostic if you use the -fno-builtin option.
The bug appears to be fixed in 4.8.0.
I think stdio.h is included by default
I try it with puts and works for me [gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)]
extern "C" { extern int puts(const char* s); }
constexpr int g() { return puts(""), 0; }
template <int N> struct X { const static int value = N; };
int n = X<g()>::value;
Edit:
#Keith Thompson
Before I wrote "included by default" I tried the code below without #include <stdio.h>. It compiles with some warnings but runs - so (for some reason) printf, scanf, puts works without #include <stdio.h>. Maybe stdio.h is not included by default, maybe library with printf, scanf, puts is linked by default.
int main()
{
char one;
printf("Hello ");
scanf("%c", &one);
puts("world!");
}
Related
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;
I'm learning now C++ I'm reading the book Effective C++ (Scott Meyers).
In the book, there is an item about const variables, and I try to work with them.
I notice something very interesting that I what to know if it bug in C++:
(I'm working with C++98 standard)
void Test(const int i)
{
int arr[i] = {0};
for (int j = 0; i > j; ++j)
{
arr[j] = i;
}
}
This function will compile and work exactly as I want (create int array on the stack with the size of 'i'. When I remove the 'const' from 'i' it won't compile.
I try this on gcc and clang.
Edit:
link to Compiler Explorer
To catch this kind of mistake in the future the compiler flag you want for both g++ and clang++ is -pedantic. And always remember to specify your language standard or you don't know what you'll get.
$ g++ -std=c++98 -pedantic c++-vla.cpp -o c++-vla
c++-vla.cpp: In function ‘void f(size_t)’:
c++-vla.cpp:3:30: warning: ISO C++ forbids variable length array ‘g’ [-Wvla]
3 | void f(const size_t x) { int g[x]; }
| ^
$ clang++ -std=c++98 -pedantic c++-vla.cpp -o c++-vla
c++-vla.cpp:3:31: warning: variable length arrays are a C99 feature [-Wvla-extension]
void f(const size_t x) { int g[x]; }
^
1 warning generated.
First of all, const in your function signature is ignored by the compiler. So the following two are equivalent:
Test(const int i) {}
Test(int i) {}
Secondly, this isn't valid C++ regardless of whether it compiles or not:
int arr[i] = {0};
It isn't valid because i is not a compile time constant i.e., the value of i has to be known at the time of compilation.
Try on Compiler Explorer
#include <iostream>
struct Index {
constexpr operator int() const { return 666; }
};
template <int i> void foo() {
std::cout << i << std::endl;
}
void wrapper(Index index) {
foo<index>();
}
int main() {
Index index;
// foo<index>(); // error: the value of ‘index’ is not usable in a constant expression
wrapper(index);
}
Hello, everyone.
I'm using a constexpr conversion of a variable "index" to an int value, which is substituted to a "foo" templated function.
If I directly call foo<index>() from "main", I get a compiler error.
If the same call is done from the "wrapper", then everything compiles and works fine.
What am I missing there?
Compile command: g++ -std=c++14 main.tex with g++ (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6).
A very similar error was reported here. It was first reported with GCC 4.9.0
In the analysis provided:
This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type.
It has since been resolved.
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.
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Is this a legitimate C++ code?
“C subset of C++” -> Where not ? examples ?
Could anybody come up with a piece of code that compiles with gcc or any other C compiler, and doesn't compile g++ or any other C++ compiler?
UPDATE:
I don't mean just keywords
UPDATE2:
Thank you All for answers. Apparently moderators were less enthusiastic than I was about subtle differences between C and C++.
UPDATE3:
to moderators: could you merge it with my previous question on the topic, as you suggested? It makes perfect sense to keep these two question together.
#include <stdlib.h>
int main()
{
char* s = malloc(128);
return 0;
}
This will compile with gcc, but not with g++. C++ requires an explicit cast from void* here, whereas C does not.
int main(int argc, char **class)
{
return !argc;
}
Edit: another example
int foo();
int main(void) {
return foo(42);
}
int foo(int bar) {
return bar - 42;
}
Try
extern int getSize();
int main()
{
char x[getSize()];
x[0] = 0;
}
int getSize()
{
return 4;
}
Remember to compile with the strict flags.
> gcc -pedantic -std=c99 t.c
> g++ -pedantic t.c
t.c: In function `int main()':
t.c:6: error: ISO C++ forbids variable length array `x'
How about
/* Within a function */
{
enum {foo} bar;
bar++;
}
That seems a pretty big breaking change in the design of C++, but it is what it is.
What about character size:
Even worse is that it compiles but produces different output at runtime.
#include <stdio.h>
int main()
{
fprintf(stdout, "%s\n", (sizeof('\xFF') == sizeof(char))?"OK":"Fail");
}
> gcc -pedantic t.c
> ./a.exe
Fail
> g++ -pedantic t.c
> ./a.exe
OK
This actually makes we wonder why this works?
fprintf(stdout, "%c%c\n", 'A', 'B');
It works on both compilers even though the size of the objects are different.
pointer arithmetics on void*:
void* t;
t++; // compiles only in gcc