constant function parameter as a static array size? - c++

I am not completely sure why this isn't working
void foo(const int a=10){
const int b = 10;
int c[a];
int d[b];
}
I thought that I say to the compiler the a is constant - I even tell it that default value is 10 :).
Why is he yelling:
1>sum_floats_txt.cpp(105): error C2057: expected constant expression
1>sum_floats_txt.cpp(105): error C2466: cannot allocate an array of constant size 0
1>sum_floats_txt.cpp(105): error C2133: 'c' : unknown size
I know what it tells me, but I do not know how to do what I want to do:
- function with static array inside of size dependable on outside constant
The function is counting something and returning the time spended on the execution (doing it in RTOS).
So I want to call this function with different parameters from main. To find out for which parameter it executes the shortest.
Is the problem in the way the static arrays works? It must have a constant size in the time of compilation. So for different static arrays I must define more of them.
Possible solution is to create more functions or more static arrays with different sizes predefined. And call them one after the other, but there are thousands of different sizes.
I do not want to do the non-automatized iteration to get the best parameters! Could arguments from main passed to the function before execution help?
VS2010 + RTX64 2013 (should not be the problem)
win7
thanks!

Don't mix up const qualified and constant.
const qualified just says that you don't have the right to modify the variable.
In C++ if a const qualified variable is also a compile time constant, the construct that you are using would be allowed. Here it is a parameter to a function, so there is no way that the compiler may know a value that it would substitute at compile time.
In C, things are different. In modern C, that is C since 1999, variable length arrays with such values that are only known during execution are allowed. Unfortunately there are still C compilers that don't conform to C99. AFAIR micorsoft compilers are among these.

The const int a argument is "read only" argument. It is not necessarily a value that the compiler knows at compile time. You can use a template argument though.
template <int N = 42>
void foo() {
int myArray[N];
}
C however does allow what you wrote there, C++ doesn't but will in C++14 with "std::dynarray".

Related

Const Int declared with stoi not considered a const

I wrote a simple test program using CGAL, and running into the following issue:
Point is defined above as
typedef K::Point_d Point;
but I don't think this is relevant.
When I attempt to compile the program as follows:
const int size = 10;
Point P[size];
g++ does so without issue.
If instead I attempt to compile:
const int size = stoi("10");
Point P[size]
I get the following error
error: variable length array of non-POD element type 'Point' (aka 'Point_d<Cartesian_d<double,
CGAL::Linear_algebraCd<double, std::__1::allocator<double> > > >')
Why is size considered a variable instead of a const when retrieved from a string?
C++ defines specific things to be constant expressions that are defined to be known at compile time - see constant_expression.
In general functions that are not defined as constexpr are not, regardless of what you pass them. You could try and force it as such:
#include<string>
constexpr int x = std::stoi("10");
int main() {
return 0;
}
but you will find this still leads to an error:
error: call to non-constexpr function 'int std::stoi(const string&, std::size_t*, int)'
so, you are out of luck as stoi is not a constant expression. If you really insist you could override this using your own implementation for example that in How do I convert a C string to a int at compile time?.
stoi is not evaluated at compile time. That means the compiler does not know how big the array should be.
if you want to do something like that you have to use a constexpr function (constexpr function). These can be evaluated at compile time, then it works.
The compiler doesn't understand the semantics of the stoi function. All it sees is you calling a function that returns an integer (whether that function can be inlined and optimized away is a seperate issue from the semantics).
To the compiler there is very little semantic difference between
const int size = stoi("10");
and
const int size = getchar();
As other answers mentioned constexpr being the exception. I just thought I'd illustrate the issue.
The first const int size = 10; is a compile time const expression and it can be computed during compilation,
but const int size = stoi("10") is not a compile time const expression hence it fails to compile.
std::stoi is not a constexpr function to evaluated on compile time.
If you want to have this functionality you may need to create a constexpr function to evaluate on compile time.
constexpr bool is_digit(char c) {
return c <= '9' && c >= '0';
}
constexpr int stoi_impl(const char* str, int value = 0) {
return *str ?
is_digit(*str) ?
stoi_impl(str + 1, (*str - '0') + value * 10)
: throw "compile-time-error: not a digit"
: value;
}
constexpr int to_int(const char* str) {
return stoi_impl(str);
}
int main() {
constexpr int size = to_int("10");
int arr[size];
}
This will compile; [copied from here]
In the first code sample
const int size = 10;
Point P[size];
the particular value of size can be used already at compile time, since it is known (you've specified it). Therefore the compiler may replace all its uses with particular value, w/o actually creating a variable.
In the second sample
const int size = stoi("10");
Point P[size]
the compiler cannot know the value, since it is deduced by the stoi function at runtime. Therefore it cannot substitute the size of the array (which must be known beforehand to determine now much memory to allocate), and you get the error.
In C++11 there is constexpr idiom, which allows some functions, declared as constexpr, be evaluated at compile time. But in your case stoi isn't constexpr function, so you cannot achieve what you want using this particular function. You can implement your own constexpr stoi, but I don't see much sence in it, since your code in this case would contain somethins like this: my_constexpr_stoi("10"), i.e. the argument is always manually written and always known beforehand. Why don't write just 10?..
To expand on kabanus’ answer, the language standard says that an array bound in C++11 must be something called an integral constant expression. C++17 relaxes this slightly and allows a few more things, but that’s not important right now.
This page at cppreference lists all the things you are not allowed to do inside a constant expression. It basically quotes the language standard.
The relevant section that allows your first example is 8a. You are not allowed to use a variable, unless it’s a const variable initialized to a constant expression. So using the name of a const variable of integral type that is initialized to a constant expression is legal, as in your first example. Numeric constants are constant expressions, so size is a const variable initialized to a constant expression, which is A-OK.
However, due to point 2, function calls are only constant expressions if they are both declared constexpr and already defined. So, for a standard library function to be usable in an array expression in your code, it would need to be declared constexpr and also defined in the header file.
The standard does not say that stoi() qualifies, although I don’t think anything in it directly forbids some implementation from providing that as an extension.

Declaring an array with constant size - compilation error

Can someone help me to explain this:
I declare a constant in the headerfile:
const int INCRSIZE;
Then in the MIL the constant is initialized:
: INCRSIZE(10)
then later on in a function in the code (its a callback-function used in a gtkmm-GUI
bool MyWindow::on_drawing_expose_event(GdkEventExpose* event)
I allocate an array on the stack using this constant
double arrPxStep[INCRSIZE];
when I compiling i get the following errors:
-expected constant expression
- cannot allocate an array if constant size 0
- arrPxStep unknown size
I know the constant is initialzed - how come the array cannot use this constant memeber-variable that was alreade initialized in the MIL?
By the looks of the code you post, INCRSIZE is a non-static member of a class. You can't use this to initialize an array, even if the value is always set to the same in the constructor. It's just the rules.
Make INCRSIZE a static const member, defined within the class, and it will work.
It is very hard for compiler to detect, that your variable INCRSIZE is const and initialized. So it processes INCRSIZE as usual integer variable. Since you set value to this variable in constructor of your class, compiler should know something about order of calls of your functions (for you it is obvious, that constructor will be the first called function, but for compiler it is not so easy to analyze it). So, it is not included in Standard of C++ (one of reasons: because it is unnecessary and hard to support).

Why do C and C++ compilers allow array lengths in function signatures when they're never enforced?

This is what I found during my learning period:
#include<iostream>
using namespace std;
int dis(char a[1])
{
int length = strlen(a);
char c = a[2];
return length;
}
int main()
{
char b[4] = "abc";
int c = dis(b);
cout << c;
return 0;
}
So in the variable int dis(char a[1]) , the [1] seems to do nothing and doesn't work at
all, because I can use a[2]. Just like int a[] or char *a. I know the array name is a pointer and how to convey an array, so my puzzle is not about this part.
What I want to know is why compilers allow this behavior (int a[1]). Or does it have other meanings that I don't know about?
It is a quirk of the syntax for passing arrays to functions.
Actually it is not possible to pass an array in C. If you write syntax that looks like it should pass the array, what actually happens is that a pointer to the first element of the array is passed instead.
Since the pointer does not include any length information, the contents of your [] in the function formal parameter list are actually ignored.
The decision to allow this syntax was made in the 1970s and has caused much confusion ever since...
The length of the first dimension is ignored, but the length of additional dimensions are necessary to allow the compiler to compute offsets correctly. In the following example, the foo function is passed a pointer to a two-dimensional array.
#include <stdio.h>
void foo(int args[10][20])
{
printf("%zd\n", sizeof(args[0]));
}
int main(int argc, char **argv)
{
int a[2][20];
foo(a);
return 0;
}
The size of the first dimension [10] is ignored; the compiler will not prevent you from indexing off the end (notice that the formal wants 10 elements, but the actual provides only 2). However, the size of the second dimension [20] is used to determine the stride of each row, and here, the formal must match the actual. Again, the compiler will not prevent you from indexing off the end of the second dimension either.
The byte offset from the base of the array to an element args[row][col] is determined by:
sizeof(int)*(col + 20*row)
Note that if col >= 20, then you will actually index into a subsequent row (or off the end of the entire array).
sizeof(args[0]), returns 80 on my machine where sizeof(int) == 4. However, if I attempt to take sizeof(args), I get the following compiler warning:
foo.c:5:27: warning: sizeof on array function parameter will return size of 'int (*)[20]' instead of 'int [10][20]' [-Wsizeof-array-argument]
printf("%zd\n", sizeof(args));
^
foo.c:3:14: note: declared here
void foo(int args[10][20])
^
1 warning generated.
Here, the compiler is warning that it is only going to give the size of the pointer into which the array has decayed instead of the size of the array itself.
The problem and how to overcome it in C++
The problem has been explained extensively by pat and Matt. The compiler is basically ignoring the first dimension of the array's size effectively ignoring the size of the passed argument.
In C++, on the other hand, you can easily overcome this limitation in two ways:
using references
using std::array (since C++11)
References
If your function is only trying to read or modify an existing array (not copying it) you can easily use references.
For example, let's assume you want to have a function that resets an array of ten ints setting every element to 0. You can easily do that by using the following function signature:
void reset(int (&array)[10]) { ... }
Not only this will work just fine, but it will also enforce the dimension of the array.
You can also make use of templates to make the above code generic:
template<class Type, std::size_t N>
void reset(Type (&array)[N]) { ... }
And finally you can take advantage of const correctness. Let's consider a function that prints an array of 10 elements:
void show(const int (&array)[10]) { ... }
By applying the const qualifier we are preventing possible modifications.
The standard library class for arrays
If you consider the above syntax both ugly and unnecessary, as I do, we can throw it in the can and use std::array instead (since C++11).
Here's the refactored code:
void reset(std::array<int, 10>& array) { ... }
void show(std::array<int, 10> const& array) { ... }
Isn't it wonderful? Not to mention that the generic code trick I've taught you earlier, still works:
template<class Type, std::size_t N>
void reset(std::array<Type, N>& array) { ... }
template<class Type, std::size_t N>
void show(const std::array<Type, N>& array) { ... }
Not only that, but you get copy and move semantic for free. :)
void copy(std::array<Type, N> array) {
// a copy of the original passed array
// is made and can be dealt with indipendently
// from the original
}
So, what are you waiting for? Go use std::array.
It's a fun feature of C that allows you to effectively shoot yourself in the foot if you're so inclined. I think the reason is that C is just a step above assembly language. Size checking and similar safety features have been removed to allow for peak performance, which isn't a bad thing if the programmer is being very diligent. Also, assigning a size to the function argument has the advantage that when the function is used by another programmer, there's a chance they'll notice a size restriction. Just using a pointer doesn't convey that information to the next programmer.
First, C never checks array bounds. Doesn't matter if they are local, global, static, parameters, whatever. Checking array bounds means more processing, and C is supposed to be very efficient, so array bounds checking is done by the programmer when needed.
Second, there is a trick that makes it possible to pass-by-value an array to a function. It is also possible to return-by-value an array from a function. You just need to create a new data type using struct. For example:
typedef struct {
int a[10];
} myarray_t;
myarray_t my_function(myarray_t foo) {
myarray_t bar;
...
return bar;
}
You have to access the elements like this: foo.a[1]. The extra ".a" might look weird, but this trick adds great functionality to the C language.
To tell the compiler that myArray points to an array of at least 10 ints:
void bar(int myArray[static 10])
A good compiler should give you a warning if you access myArray [10]. Without the "static" keyword, the 10 would mean nothing at all.
This is a well-known "feature" of C, passed over to C++ because C++ is supposed to correctly compile C code.
Problem arises from several aspects:
An array name is supposed to be completely equivalent to a pointer.
C is supposed to be fast, originally developerd to be a kind of "high-level Assembler" (especially designed to write the first "portable Operating System": Unix), so it is not supposed to insert "hidden" code; runtime range checking is thus "forbidden".
Machine code generrated to access a static array or a dynamic one (either in the stack or allocated) is actually different.
Since the called function cannot know the "kind" of array passed as argument everything is supposed to be a pointer and treated as such.
You could say arrays are not really supported in C (this is not really true, as I was saying before, but it is a good approximation); an array is really treated as a pointer to a block of data and accessed using pointer arithmetic.
Since C does NOT have any form of RTTI You have to declare the size of the array element in the function prototype (to support pointer arithmetic). This is even "more true" for multidimensional arrays.
Anyway all above is not really true anymore :p
Most modern C/C++ compilers do support bounds checking, but standards require it to be off by default (for backward compatibility). Reasonably recent versions of gcc, for example, do compile-time range checking with "-O3 -Wall -Wextra" and full run-time bounds checking with "-fbounds-checking".
C will not only transform a parameter of type int[5] into *int; given the declaration typedef int intArray5[5];, it will transform a parameter of type intArray5 to *int as well. There are some situations where this behavior, although odd, is useful (especially with things like the va_list defined in stdargs.h, which some implementations define as an array). It would be illogical to allow as a parameter a type defined as int[5] (ignoring the dimension) but not allow int[5] to be specified directly.
I find C's handling of parameters of array type to be absurd, but it's a consequence of efforts to take an ad-hoc language, large parts of which weren't particularly well-defined or thought-out, and try to come up with behavioral specifications that are consistent with what existing implementations did for existing programs. Many of the quirks of C make sense when viewed in that light, particularly if one considers that when many of them were invented, large parts of the language we know today didn't exist yet. From what I understand, in the predecessor to C, called BCPL, compilers didn't really keep track of variable types very well. A declaration int arr[5]; was equivalent to int anonymousAllocation[5],*arr = anonymousAllocation;; once the allocation was set aside. the compiler neither knew nor cared whether arr was a pointer or an array. When accessed as either arr[x] or *arr, it would be regarded as a pointer regardless of how it was declared.
One thing that hasn't been answered yet is the actual question.
The answers already given explain that arrays cannot be passed by value to a function in either C or C++. They also explain that a parameter declared as int[] is treated as if it had type int *, and that a variable of type int[] can be passed to such a function.
But they don't explain why it has never been made an error to explicitly provide an array length.
void f(int *); // makes perfect sense
void f(int []); // sort of makes sense
void f(int [10]); // makes no sense
Why isn't the last of these an error?
A reason for that is that it causes problems with typedefs.
typedef int myarray[10];
void f(myarray array);
If it were an error to specify the array length in function parameters, you would not be able to use the myarray name in the function parameter. And since some implementations use array types for standard library types such as va_list, and all implementations are required to make jmp_buf an array type, it would be very problematic if there were no standard way of declaring function parameters using those names: without that ability, there could not be a portable implementation of functions such as vprintf.
It's allowed for compilers to be able to check whether the size of array passed is the same as what expected. Compilers may warn an issue if it's not the case.

Expected constant in 2d array

double rainPerMonth(const int YEARS)
{
int monthYear[MONTHS][YEARS];
// ...
}
Visual Studio shows a squiggly line underneath the array declaration, saying that YEARS must be a constant when I'm creating the array. Is this an IDE issue because the variable has yet to be initialized, or am I writing this incorrectly?
MONTHS is already declared globally.
An array size must be a constant expression - that is, a value known at compile time. (Some compilers offer C-style variable-length arrays as a non-standard extension, but I don't think Visual C++ does. Even if it does, it's better not to rely on such extensions.)
A function argument isn't known at compile time, so can't be used as an array size. Your best option is here is probably
std::vector<std::array<int, MONTHS>> monthYear(YEARS);
In C++, an array must be sized at compile time. What you are attempting to do is declare one that is sized at runtime. In the function you've declared, YEARS is only constant within the scope of the function. You could call it rainPerMonth(someInt); where someInt is the result of some user input (which shows you that the result is not a compile-time constant).
Variable Length Arrays are an extension to C, but not C++. To do what you want, you can use dynamic memory, or a std::vector.
I think your problem lies in the fact that C++ wants a constant in the sense of compile-time constant to create your variable monthYear. If you pass it as a function, it need not be known at compile time? For example:
const int x=2;
const int y=3;
char xyChoice;
std::cin >> xyChoice;
if (xyChoice == 'x')
rainPerMonth(x);
else
rainPerMonth(y);
I'm unsure, but it seems to me like this would give you a constant int being passed to your function, but the compiler wouldn't know what size to create an array for before runtime?

usage of const in c++

I am new to C++.I was going through a C++ book and it says
const int i[] = { 1, 2, 3, 4 };
float f[i[3]]; // Illegal
It says the declaration of the float variable is invalid during compilation.Why is that?
Suppose if we use
int i = 3;
float f[i];
It works.
What is the problem with the first situation?
Thanks.
So the first is illegal because an array must have a compile-time known bound, and i[3], while strictly speaking known at compile time, does not fulfill the criteria the language sets for "compile-time known".
The second is also illegal for the same reason.
Both cases, however, will generally be accepted by GCC because it supports C99-style runtime-sized arrays as an extension in C++. Pass the -pedantic flag to GCC to make it complain.
Edit: The C++ standard term is "integral constant expression", and things qualifying as such are described in detail in section 5.19 of the standard. The exact rules are non-trivial and C++11 has a much wider range of things that qualify due to constexpr, but in C++98, the list of legal things is, roughly:
integer literals
simple expressions involving only constants
non-type template parameters of integral type
variables of integral type declared as const and initialized with a constant expression
Your second example doesn't work and it shouldn't work.
i must be constant. This works
const int i = 3;
float f[i];
Just to expound on Sebastian's answer:
When you create a static array, the compiler must know how much space it needs to reserve. That means the array size must be known at compile-time. In other words, it must be a literal or a constant:
const int SIZE = 3;
int arr[SIZE]; // ok
int arr[3]; // also ok
int size = 3;
int arr[size]; // Not OK
Since the value of size could be different by the time the array is created, the oompiler won't know how much space to reserve for the array. If you declare it as const, it knows the value will not change, and can reserve the proper amount of space.
If you need an array of a variable size, you will need to create it dynamically using new (and make sure to clean it up with delete when you are done with it).
For arrays with lengths known only at runtime in C++ we have std::vector<T>. For builtin arrays the size must be known at compile-time. This is also true for C++11, although the much older C99-standard already supports dynamic stack arrays. See also the accepted answer of Why doesn't C++ support dynamic arrays on the stack?