// sizeofarray.cpp
#include <iostream>
template <typename T,int N>
int size(T (&Array)[N])
{
return N;
}
int main()
{
char p[]="Je suis trop bon, et vous?";
char q[size(p)]; // (A)
return 0;
}
I heard that an array size in C++ must be a constant expression. So char q[size(p)] is invalid, am I right? But I got no errors when I tried
g++ -Wall sizeofarray.cpp
Why?
Like Prasoon says, it's not a constant expression. For now, you can get a constant-expression value of the size of an array like this:
template <std::size_t N>
struct type_of_size
{
typedef char type[N];
};
template <typename T, std::size_t Size>
typename type_of_size<Size>::type& sizeof_array_helper(T(&)[Size]);
#define sizeof_array(pArray) sizeof(sizeof_array_helper(pArray))
Explanation here. You basically encode the size of the array into the size of a type, then get the sizeof of that type, giving you:
char q[sizeof_array(p)];
I heard that an array size in C++ must be a constant expression.
Correct
So char q[size(p)] is invalid, am I right?
According to ISO C++, yes!
But I got no errors when I tried
g++ -Wall sizeofarray.cpp
That's because g++ supports VLA (Variable Length Array) as an extension.
In C++0x there is constexpr feature with the help of which you can write
constexpr int size(T (&Array)[N])
{
return N;
}
and then char q[size(p)] would be legal.
EDIT : Also read this article [blog whatever]
I beg to differ with all the answers here. The code show is perfectly fine except for a minor issue (which is definitely not VLA)
template <typename T,int N>
int size(T (&Array)[N])
{
return N;
}
int main()
{
char p[]="Je suis trop bon, et vous?";
char q[sizeof(p)]; // (A), not sizeof and not size as in OP
return 0;
}
I was wondering that the result of the sizeof is always a const value, and hence the code should be fine.
The above code builds fine on VS 2010 and Comeau(strict mode)
$5.3.3/6- "The result is a constant of
type size_t. [Note: size_t is defined
in the standard header (18.1)."
I use g++ 4.4.3 and have the following alias so that I never forget to turn on the warnings:
$ alias g++
alias g++='g++ -ansi -pedantic -Wall -W -Wconversion -Wshadow -Wcast-qual -Wwrite-strings'
If compiled with the above, there would be some warnings. Following steps show how different options show different warnings.
Compilation with no warning option does not show any warning
$ \g++ sizeofarray.cpp
Turning on -Wall
$ \g++ -Wall sizeofarray.cpp
sizeofarray.cpp: In function ‘int main()’:
sizeofarray.cpp:12: warning: unused variable ‘q’
Turning on -Wextra
$ \g++ -Wall -Wextra sizeofarray.cpp
sizeofarray.cpp: In function ‘int main()’:
sizeofarray.cpp:12: warning: unused variable ‘q’
sizeofarray.cpp: At global scope:
sizeofarray.cpp: In instantiation of ‘int size(T (&)[N]) [with T = char, int N = 27]’:
sizeofarray.cpp:12: instantiated from here
sizeofarray.cpp:4: warning: unused parameter ‘Array’
Finally turning on -pedantic to catch the real problem
$ \g++ -Wall -Wextra -pedantic sizeofarray.cpp
sizeofarray.cpp: In function ‘int main()’:
sizeofarray.cpp:12: warning: ISO C++ forbids variable length array ‘q’
sizeofarray.cpp:12: warning: unused variable ‘q’
sizeofarray.cpp: At global scope:
sizeofarray.cpp: In instantiation of ‘int size(T (&)[N]) [with T = char, int N = 27]’:
sizeofarray.cpp:12: instantiated from here
sizeofarray.cpp:4: warning: unused parameter ‘Array’
Related
gcc5.4 doesn't compile the following code:
// source.cpp
int nonconstexprfunc()
{
return 14;
}
constexpr int func(int n)
{
if (n < 0)
return nonconstexprfunc();
return n*n;
}
int main()
{
constexpr int t1 = func(0);
return 0;
}
The command I use:
$ g++ -std=c++14 -c source.cpp
The output:
In function ‘constexpr int func(int)’:
error: ‘constexpr int func(int)’ called in a constant expression
constexpr int t1 = func(0);
In function ‘int main()’:
error: ‘constexpr int func(int)’ called in a constant expression
constexpr int t1 = func(0);
But I can compile that source.cpp using gcc6.4. Doesn't gcc5.4 fully support constexpr functions?
More interestingly I can compile that source.cpp using icpc (Intel C++ compiler) that uses gcc5.4 - I suppose there must be an option to compile that code using gcc5.4.
$ icpc -v
icpc version 19.0 (gcc version 5.4.0 compatibility)
$ icpc -std=c++14 -c source.cpp
no errors
The first limitation is concerning the use gcc 5.4 with -std=c++11 which produces the error because of the two return statement see The body of constexpr function not a return-statement so in order to lift your first issue you need to use -std=c++14
It then produces
'#1 with x86-64 gcc 5.4
: In function 'constexpr int func(int)':
:10:32: error: call to non-constexpr function 'int
nonconstexprfunc()'
return nonconstexprfunc(); ^
: In function 'int main()':
:16:28: error: 'constexpr int func(int)' called in a constant
expression
constexpr int t1 = func(0);
Compiler returned: 1
This next error produced seems to be a known GCC bug (misinterpretation of c++14) see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86678
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67026
You can also check out calling non constexpr function from constexpr allowed in some conditions
However judging from the error it produces:
It seems pretty obvious that doing
constexpr int nonconstexprfunc()
{
return 14;
}
will solve the error and will be more efficient in your case.
Check the difference with https://www.godbolt.org/ of adding constexpr or not using gcc 8.2 for example.
int a;
cin >> a;
int ints[a];
Why does this not throw any kind of warning while compiling? How do I know when this array thing is actually using the heap or the stack?
g++ -std=c++11 -Wall *.cpp -o main
ISO C++ disallows the use of variable length arrays, which g++ happily tells you if you increase the strictness of it by passing it the -pedantic flag.
Using -pedantic will issue a warning about things breaking the standard. If you want g++ to issue an error and with this refuse compilation because of such things; use -pedantic-errors.
g++ -Wall -pedantic -std=c++11 apa.cpp
apa.cpp: In function ‘int main(int, char**)’:
apa.cpp:8:13: warning: ISO C++ forbids variable length array ‘ints’ [-Wvla]
int ints[a];
^
apa.cpp:8:7: warning: unused variable ‘ints’ [-Wunused-variable]
int ints[a];
^
When I compile the code below with g++ 4.8.1 (64bit) in this way:
$ g++ -Wconversion -o main main.cpp
I get this result:
main.cpp: In function ‘int main()’:
main.cpp:12:20: warning: conversion to ‘int’ from ‘long unsigned int’ may alter its value [-Wconversion]
int i = sizeof(x)/sizeof(x[0]);
^
My expectation would be that the compiler should be able to evaluate the expression at compile time. If you make a similar program in plain c, gcc works like a charm.
Should this be considered a bug in g++ (e.g. clang++ does not have this problem)?
if you change the problematic line to something like:
char c = 0x10000000/0x1000000;
then the compiler does not complain. This suggest that some constant evaluation is done before warning generation.
main.cpp:
#include <iostream>
struct foo {
int a;
int b;
};
foo x[50];
int main()
{
int i = sizeof(x)/sizeof(x[0]);
std::cout << i << std::endl;
return 0;
}
int i = sizeof(x)/sizeof(x[0]);
//int <-- std::size_t <-- std::size_t / std::size_t
The type of the expression sizeof(x)/sizeof(x[0]) is std::size_t which on your machine is unsigned long int. So conversion from this type to int is data-loss, if the source is bigger in size than the target.
Though, I agree that in your case, there would not be actual data-loss if the compiler actually computes the value, but I guess it applies -Wconversion before the actual computation.
sizeof() returns you std::size_t not int! So cast it or declare i as std::size_t.
std::size_t i = sizeof(x)/sizeof(x[0]);
int a;
cin >> a;
int ints[a];
Why does this not throw any kind of warning while compiling? How do I know when this array thing is actually using the heap or the stack?
g++ -std=c++11 -Wall *.cpp -o main
ISO C++ disallows the use of variable length arrays, which g++ happily tells you if you increase the strictness of it by passing it the -pedantic flag.
Using -pedantic will issue a warning about things breaking the standard. If you want g++ to issue an error and with this refuse compilation because of such things; use -pedantic-errors.
g++ -Wall -pedantic -std=c++11 apa.cpp
apa.cpp: In function ‘int main(int, char**)’:
apa.cpp:8:13: warning: ISO C++ forbids variable length array ‘ints’ [-Wvla]
int ints[a];
^
apa.cpp:8:7: warning: unused variable ‘ints’ [-Wunused-variable]
int ints[a];
^
Why do I get the error
Expression Syntax
on the m[0]= line in the code below?
struct menu{
int code;
char name[30];
}m[5];
int main() {
clrscr();
m[0]={1,"MAGGI"}; //try to check whether this works or not and it didn't actually
<<endl;
cout<<m[0].code<<"\t"<<m[0].name;
getch();
return 0;
}
Succinctly — you can't do that in C++ with the struct menu as written with just default constructors.
In C99, you could use:
m[0] = (struct menu){ 1, "MAGGI" }; // C99 compound literal
Even in C++11, that (meaning 'using a compound literal') is not valid.
The unadorned use of endl; attempts to generate a function pointer, but the function is overloaded so it doesn't compile. You should add an << endl to the end of the output, though.
G++ allows C99-style compound literals
It is interesting that GCC (tested GCC 4.7.1 on Mac OS X 10.8.4) accepts the compound literal notation, even with stringent warnings, but this is a GCC/G++ extension over standard C++:
g++ -O3 -g -Wall -Wextra -c x91.cpp
Code:
#include <iostream>
using namespace std;
struct menu
{
int code;
char name[30];
} m[5];
int main()
{
m[0] = (struct menu){ 1, "MAGGI" };
cout << m[0].code << "\t" << m[0].name << endl;
return 0;
}
You have to provoke G++ fairly hard to get it to complain:
$ g++ -O3 -g -Wall -Wextra -std=c++98 -pedantic x91.cpp -o x91
x91.cpp: In function ‘int main()’:
x91.cpp:11:34: warning: ISO C++ forbids compound-literals [-pedantic]
$ g++ -O3 -g -Wall -Wextra -std=c++11 -pedantic x91.cpp -o x91
x91.cpp: In function ‘int main()’:
x91.cpp:11:34: warning: ISO C++ forbids compound-literals [-pedantic]
$
C++ 2011 and 'list initialization' or 'extended initializer lists'
I think section 8.5 Initializers in general and 8.5.4 List-initialization in particular mean that you can in fact write what you originally had, if your class (structure in the example) has the appropriate support.
Consider this minor variant on your original code:
#include <iostream>
#include <cstring>
using namespace std;
struct menu
{
int code;
char name[30];
menu(int c, const char *n) : code(c) { strncpy(name, n, sizeof(name)); name[sizeof(name)-1] = '\0'; }
menu() : code(0) { name[0] = '\0'; }
} m[5];
int main()
{
menu m0 = { 2, "MAGGI 2" };
m[0] = (struct menu){ 1, "MAGGI 1" };
m[1] = { 3, "MAGGI 3" };
cout << m[0].code << "\t" << m[0].name << endl;
cout << m0.code << "\t" << m0.name << endl;
cout << m[1].code << "\t" << m[1].name << endl;
return 0;
}
This code compiles OK under G++, subject to warnings about compound literals not being part of standard C++, when compiled as shown:
$ g++ -O3 -g -Wall -Wextra -std=c++11 -pedantic x91.cpp -o x91
x91.cpp: In function ‘int main()’:
x91.cpp:16:39: warning: ISO C++ forbids compound-literals [-pedantic]
$ ./x91
1 MAGGI 1
2 MAGGI 2
3 MAGGI 3
$
We can debate the wisdom of the use of strncpy() — that is tangential to the subject under discussion. The default constructor is needed to allow the array to be defined. The other constructor is necessary for the extended list initialization. Comment out the non-default constructor and you get scads of compilation messages:
$ g++ -O3 -g -Wall -Wextra -std=c++11 -pedantic x91.cpp -o x91
x91.cpp: In function ‘int main()’:
x91.cpp:15:29: error: could not convert ‘{2, "MAGGI 2"}’ from ‘<brace-enclosed initializer list>’ to ‘menu’
x91.cpp:16:39: warning: ISO C++ forbids compound-literals [-pedantic]
x91.cpp:16:39: error: no matching function for call to ‘menu::menu(<brace-enclosed initializer list>)’
x91.cpp:16:39: note: candidates are:
x91.cpp:10:5: note: menu::menu()
x91.cpp:10:5: note: candidate expects 0 arguments, 2 provided
x91.cpp:5:8: note: constexpr menu::menu(const menu&)
x91.cpp:5:8: note: candidate expects 1 argument, 2 provided
x91.cpp:5:8: note: constexpr menu::menu(menu&&)
x91.cpp:5:8: note: candidate expects 1 argument, 2 provided
x91.cpp:17:26: error: no match for ‘operator=’ in ‘m[1] = {3, "MAGGI 3"}’
x91.cpp:17:26: note: candidates are:
x91.cpp:5:8: note: menu& menu::operator=(const menu&)
x91.cpp:5:8: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const menu&’
x91.cpp:5:8: note: menu& menu::operator=(menu&&)
x91.cpp:5:8: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘menu&&’
$
In C++98 mode (with both constructors present), you get a warning about using 'extended initializer lists' outside C++11 compliance mode:
$ g++ -O3 -g -Wall -Wextra -std=c++98 -pedantic x91.cpp -o x91
x91.cpp: In function ‘int main()’:
x91.cpp:15:29: error: in C++98 ‘m0’ must be initialized by constructor, not by ‘{...}’
x91.cpp:16:39: warning: ISO C++ forbids compound-literals [-pedantic]
x91.cpp:17:26: warning: extended initializer lists only available with -std=c++11 or -std=gnu++11 [enabled by default]
$
Declare constructors for the struct and use them. Also try using std::string over char[]. It is not possible to do as you have done. the constructor could be as
menu(int _code, string _name):code(_code), name(_name)
{} //changing name to string
with that, don't forget to declare a default constructor as well as you are creating an array of struct variables