I'm using a library which for one certain feature involves variables like so:
extern const u8 foo[];
extern const u8 bar[];
I am not allowed to rename these variables in any way.
However, I like to be able to access these variables through an array (or other similar method) so that I do not need to continually hardcode new instances of these variables into my main code.
My first attempt at creating an array is as follows:
const u8* pl[] = {
&foo,
&bar
};
This gave me the error cannot convert 'const u8 (*)[]' to 'const u8*' in initialization, and with help elsewhere along with some Googling, I changed my array to this:
u8 (*pl)[] = {
&foo,
&bar
};
Upon compiling I now get the error scalar object 'pl' requires one element in initializer.
Does anyone have any ideas on what I'm doing wrong? Thanks.
An array of pointers to arrays only works if foo and bar have exactly the same size, and that size is known at compile time in your translation unit.
const u8 (*pl[])[32] = {&foo, &bar};
If that is not the case, you must use an array of pointers to bytes.
const u8 *pl[] = {foo, bar};
As the arrays don't have a size in their declaration is there any reason you can't just an array of pointers to their first elements?
E.g.
const u8* pl[] = { foo, bar };
If you wanted an array of pointers to arrays I think that you would need to do:
const u8 (*pl[])[] = { &foo, &bar };
but I don't see that it really has any advantage over the previous solution.
extern const int a[];
const int * aa[] = { a };
Remove the &. An array decays normally into a pointer.
typedef int u8; // Using int as I don't know what a u8 is.
const u8 foo[] = { 1, 2, 3};
const u8 bar[] = { 1 };
const u8* pl[] = {
foo,
bar
};
Related
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
I have looked at all the other posts with a similar topic, and none help, so please don't flag as a duplicate.
I am defining in main() a const int SIZE = 20;. Then, I pass this as an argument to my function, Mode:
int* Mode(int* numbers, int & mode, const int SIZE)
{
int occurences[SIZE];
// Calcualte mode
}
However, I get the error, expression must have a constant value.
My function call (in main) looks like this:
int* occurencesPtr = Mode(numbersPtr, mode, SIZE);
With SIZE being defined at the beginning to the literal 20.
I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.
I have even tried passing to the function a const int * const SIZEPtr = &SIZE, but that didn't work either. Help?
EDIT: I am not trying to use a variable size!! Notice that I have made SIZE a const everywhere! I just want to use that same SIZE constant to declare my array.
EDIT: Dynamic arrays are not what I need. I just want a normal, named, array, defined with a constant size value passed to the function.
There is a misconception here with what const means, probably because it's a little confusing that this works:
const int SIZE = 20;
int array[SIZE];
but this doesn't:
void foo(const int SIZE) {
int array[SIZE];
// ...
}
const int SIZE = 20;
foo(SIZE);
The issue is that the array size in an array declaration must be a core constant expression. Simplified, that means an expression that's evaluatable at compile time to be a constant. That is true in the first case (you can see that SIZE is the integral constant 20) but that is not true in the second case. There, the SIZE function parameter is just const - in the sense that it is nonmodifiable - and not a core constant expression. You can see the difference in that I can call foo() with something that is clearly unknowable until runtime:
int x;
if (std::cin >> x) {
foo(x);
}
In order to pass an argument into foo, and have that argument be used as an array bound, it is not enough to have it be const - the actual integral value must be encoded into the type (unless you call foo() as constexpr which I'm assuming is not the case here). In which case, you'd have to do something like:
template <int SIZE>
void foo() { ... }
const int SIZE = 20;
foo<SIZE>();
or:
template <int SIZE>
void foo(std::integral_constant<int, SIZE > ) { ... }
const int SIZE = 20;
foo(std::integral_constant<int, SIZE>{} );
or simply have SIZE be a global constant or otherwise accessible to foo() in a way that doesn't have to do with its arguments.
Or, there's always the simple option: use std::vector:
void foo(const int SIZE) {
std::vector<int> v(SIZE);
...
}
I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.
Option 1
Instead of defining SIZE in main, add a constexpr function. Use the constexpr function instead of passing the size.
constexpr int getSize()
{
return 20;
}
int* Mode(int* numbers, int & mode)
{
int occurences[getSize()];
// ...
}
Option 2
Use std::vector instead of array.
int* Mode(int* numbers, int & mode, int size)
{
std::vector<int> occurences[size];
// ...
}
Option 3
Use a function template.
template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
int occurences[SIZE];
// ...
}
Option 4
Use a function template and std::array.
template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
std::array<int, SIZE> occurences;
// ...
}
You're confusing things. A constant expression has nothing to do with const (at least not that much) ;).
let's think we are the compiler and face this function:
void foo(const int SIZE) { }
The constmerely says "we are not able to change the function-local variable SIZE inside the function body.
We need to compile it without assuming that SIZE is compile time constant. Why?
Because there is noone stoping us from doing something like:
int i{};
std::cin >> i;
foo(i);
You can pass any (matching/convertible) value to a by value const function argument.
What should happen when the compiler assumed the value passed to foo was a compile time constant expression?
If you want to pass compile time constants, use templates and while you're at it use std::array instead of T[N]:
template<std::size_t N>
void foo()
{
std::array<int, N> occurences;
}
const isn't doing what you think it's doing in your Mode function.
When const is used in function definition, const is simply telling the compiler that the function will not change the argument declared const inside of the scope of it's function. But that does not make the argument a constant, it is actually called a constant expression. Some compilers enforce this, others do not, and so will allow you to change const expressions (arguments passed with const keyword).
In order to use a globally accessible constant value which you can use, like SIZE, you'll need to declare a global constant before the function is called; which could be declared outside of main(), or at least outside the scope of all other functions but main(), if you must declare all inside main. Pass the global constant to the Mode function just as you would any other variable.
Oh, and, main() needs a return type.
I've edited the code to meet your specific constraints.
Here is a variation on your original code:
int main(){
//Declare constants first.
const int SIZE = 20; /*Could declare here instead.*/
//Declare variables next.
int *intPtr = 0; // to hold the pointer passed from Mode.
int *numbersPointer = 0;
int mode = 0;
//Define Mode (using OP's code.)
int* Mode(int* numbers, int & mode, const int size){
int occurences[size];
// Calculate mode
}
/*Now use constants, variables, and functions.*/
intPtr = Mode(numbersPointer, mode, SIZE); //Call mode.
return 0;
}
I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:
#define foo_init { 1, 2, 3 }
I'm also trying to write portable code, so I need a solution that's valid C89 or C99.
Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?
Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?
In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.
A "large" object is never a constant expression in C, even if the object is declared as const.
Moreover, in C language, the term "constant" refers to literal constants (like 1, 'a', 0xFF and so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constants in C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.
For example, this is NOT a constant
const int N = 5; /* `N` is not a constant in C */
The above N would be a constant in C++, but it is not a constant in C. So, if you try doing
static int j = N; /* ERROR */
you will get the same error: an attempt to initialize a static object with a non-constant.
This is the reason why, in C language, we predominantly use #define to declare named constants, and also resort to #define to create named aggregate initializers.
It's a limitation of the language. In section 6.7.8/4:
All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.
If you can change my_foo so it does not have static storage, you would be okay:
int main()
{
foo_t my_foo = foo_init;
return 0;
}
2021: For who reaches this post because of arm-none-eabi-gcc.exe compile error on STM32 MCUs:
Change your toolchain to gnu-tools-for-stm32.9-2020-q2-update.
From GCC V8.1+, nested constant initializer is supported and the code below will be compiled.
const int a = 1;
const int b = a +1;
typedef struct foo_t {
int a, b, c;
} foo_t;
const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;
int main()
{
return 0;
}
arm-none-eabi-gcc.exe in gnu-tools-for-stm32.7-2018-q2-update is based on gcc v7.3.1 and the code above will not compile! But gnu-tools-for-stm32.9-2020-q2-update uses gcc v9.3.1 and will compile.
For more info see these:
Why "initializer element is not a constant" is... not working anymore?
and
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69960#c18
Just for illustration by compare and contrast
The code is from http://www.geeksforgeeks.org/g-fact-80/
/The code fails in gcc and passes in g++/
#include<stdio.h>
int initializer(void)
{
return 50;
}
int main()
{
int j;
for (j=0;j<10;j++)
{
static int i = initializer();
/*The variable i is only initialized to one*/
printf(" value of i = %d ", i);
i++;
}
return 0;
}
This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:
#include <stdio.h>
typedef struct foo_t {
int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
const foo_t *const f1 = &s_FooInit;
const foo_t *const f2 = s_pFooInit;
printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
return 0;
}
There are basically two sorts of initialization: at compile time, and at run time.
The initialization for static-storage variable belongs to the compile-time initialization. Note that the static-storage variable includes:
global variable without the static keyword
global variable with the static keyword
local variable with the static keyword
But what is the principle behind this rule?
In my mind it's simple to explain.
Before the completion of compilation, the values of these variables would be stored into the executable file. And at that time no code can run!
gcc 7.4.0 can not compile codes as below:
#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
printf("%s - %s\n", str1, str2);
return 0;
}
constchar.c:3:21: error: initializer element is not constant
const char * str2 = str1;
In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.
A function name is of course a compile-time constant.So this code works:
void func(void)
{
printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
f();
return 0;
}
I had this error in code that looked like this:
int A = 1;
int B = A;
The fix is to change it to this
int A = 1;
#define B A
The compiler assigns a location in memory to a variable. The second is trying a assign a second variable to the same location as the first - which makes no sense. Using the macro preprocessor solves the problem.
I received lecture slides for C++ that merely mention these without explaining what they mean and what are their differences:
int (*arr)[]={...};
int *(arr[])={...};
int (&arr)[]={...};
int &(arr[])={...}; // not allowed?
What do each of these mean? I tried running a program with some of these, but I'm getting errors because I don't know what to put in the initialization list.
int (*arr)[] = { ... };
This is not an array at all. This is a pointer to an array of unknown size. Note that this a scalar type. It is just a data pointer, no different in nature from any other data pointer. Which means that the only way to use { ... } initializer with it is to specify a single value of proper type inside the { ... }. E.g.
int (*arr)[] = { nullptr };
which is the same as
int (*arr)[] = nullptr;
int *(arr[]) = { ... };
This is indeed an array. The same thing can be expressed as
int *arr[] = { ... };
This is an array of int * pointers. It size will depend on how many initializers are supplied in { ... }. E.g.
int *arr[] = { nullptr, &some_int, &some_other_int };
declares arr as an array of 3 pointers of type int *.
int (&arr)[] = { ... };
This is not an array per se. This is a reference to an array of unknown size. Again, the only legal { ... } initializer in this case would be just one lvalue of type int [] inside the { ... }. If the array was declared const, you'd be able to attach it to a temporary array of ints using this syntax, e.g.
const int (&arr)[] = { 1, 2, 3 };
But without const it is not possible. (I have my doubts about the legality of this even with const though. GCC accepts it.)
int &(arr[]) = { ... };
This is an attempt to declare an array of references. Not allowed.
You need to use the Clockwise/Spiral Rule.
int (*arr)[]={...}; // pointer to array of int
int *(arr[])={...}; // array of int pointers
int (&arr)[]={...}; // a reference to an array of int
int &(arr[])={...}; // an array of int references
The last one though is illegal: Why arrays of references are illegal?
I asked this question: Array Equivalent of Bare-String
To which the answer was C++ doesn't provide this functionality for const int*s. Which is disappointing. So my question then is: In practice how do I get around this limitation?
I want to write a struct like this:
struct foo{
const char* letters = "abc";
const int* numbers = ???
};
I cannot:
&{1, 2, 3} cause I can't take the address of an r-value
array<int, 3>{{1, 2, 3}}.data() cause the memory is cleaned up immediately after initialization
const int* bar(){ return new int[3]{1, 2, 3}; } cause nothing will delete this pointer
I know that I can use an auto pointer to get around this. I am not suggesting that struct foo is good code, I am trying to illustrate that the compiler makes a provision to store the const array "abc" in memory and clean it up on program exit, I want there to be a way to do that for ints as well.
Is there a way to accomplish this?
How about a static which you point to - I think this what the compiler pretty much does internally for "strings literals" anyway?
static const int Numbers[] = {1, 2, 3};
struct foo{
const char* letters = "abc";
const int* numbers = Numbers;
};
String literals are all you get. However, they are also enough to cover most integral data. In your case you can use
L"\1\2\3"
to get a compiler-managed array of wide characters. C++11 and later also support u8, u16, and u32 strings.
We can accomplish this using Ben Voigt's answer:
const int* numbers = sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U"\1\2\3") : reinterpret_cast<const int*>(u"\1\2\3");
The ternary is compiled out as is evidenced by the fact that you can declare numbers as constexpr.
There are a couple drawbacks to this implementation:
This is actually a wchar_t string literal you will get a terminating 0 element in addition to any characters you specify
This assumes that an int will be either 32-bits or 16-bits, if that's not the case this will try to cast from a char16_t to a whatever sized int and you will have major problems
In any case we can simplify this into a macro:
#define QUOTATION(x) sizeof(int) == sizeof(char32_t) ? reinterpret_cast<const int*>(U ## x) : reinterpret_cast<const int*>(u ## x)
Which can be used like:
const int* numbers = QUOTATION("\1\2\3");
I was thinking about this the other day and I am curious if this is a bad idea...
Lets say there is a structure that contains a pointer to a string array.
Would the memcpy() copy the 'name' array pointer in the below example?
Edit: The std is inaccessible in this example.
struct charMap
{
unsigned char * name;
unsigned char id;
};
typedef struct charMap CharMapT;
class ABC
{
public:
ABC(){}
void Function();
CharMapT* structList;
}
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
structList = new CharMapT[sizeof(list)];
memcpy(structList, &list, sizeof(list));
}
There are several errors in the code presented, which I will talk about first, followed by my stock-diatribe of pointers vs. arrays.
struct charMap
{
unsigned int * name;
unsigned int id;
};
typedef struct charMap CharMapT;
This declares a structure type that includes a pointer to unsigned int as the first member (name) and an int as the second member (id). On a 32-bit system with default byte packing this will be 8 bytes wide (32-bit pointer = 4bytes, 32-bit signed int=4bytes). If this is a 64-bit machine the pointers will be 8 bytes wide, the int still-likely 32-bits wide, making the structure size 12 bytes.
Questionable Code
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
structList = new CharMapT[sizeof(list)];
memcpy(structList, &list, sizeof(list));
}
This allocates dynamic array of CharMapT structs. How many? More than you think. The sizeof(list) will return the byte-count of the list[] array. Since a CharMapT structure is 8 bytes wide (see above) this will 3 * 8, or 24 CharMapT items (36 items if using 64-bit pointers).
We then memcpy() 24 bytes (or 36 bytes) from list (the & in &list is unecessary) to the newly allocated memory. this will copy over 3 CharMapT structures, leaving the other 21 we allocated untouched (beyond their initial default construction).
Note: you're initializing a const char * to a field declared as unsigned int *, so if this even compiled the fundamental data type would be different. Assuming you fixed your structure and change the pointer type to const char *, the addresses of the static string constants (the addresses of the "NAME" constants) somewhere in your const data segment will be assigned to the pointer variables of the elements in structList[0].name, structList[2].name, and structList[3].name respectively.
This will NOT copy the data pointed to. it will only copy the pointer values. If you want copies of the data then you must raw-allocate them (malloc, new, whatever).
Better still, use an std::vector<CharMapT>, use std::string for CharMapT::name, and use std::copy() to replicate the source (or even direct-assignment).
I hope that explains what you were looking for.
Pointer vs. Array Diatribe
Never confuse a pointer with an array. A pointer is a variable that holds an address. Just like an int variable hold an integer value, or a char variable holds a character type, the value held in a pointer is an address
An array is different. It is also a variable (obviously), but it cannot be an l-value, and nearly every place it is typically used a conversion happens. Conceptually that conversion results in a temporary pointer that points to the data type of the array, and holds the address of the first element. There are times when that concept does not happen (such as the applying the address-of operator).
void foo(const char * p)
{
}
char ar[] = "Hello, World!";
foo(ar); // passes 'ar', converted to `char*`, into foo.
// the parameter p in foo will *hold* this address
or this:
char ar[] = "Goodbye, World!";
const char *p = ar; // ok. p now holds the address of first element in ar
++p; // ok. address in `p` changed to address (ar+1)
but not this:
char ar[] = "Goodbye, World!";
++ar; // error. nothing to increment.
It won't copy your actual data pointed by name. It will copy the pointer and you'll have 2 pointers to the same place in 2 objects (for each pair of objects in 2 arrays).
All you really need to know here is that memcpy will give you a bit for bit copy of the original. So what you'll have is two pointers with the same value (i.e., an address) which refer to the same data.
On a side note, you have declared name as a pointer to int, which is of course wrong here. It should be a const char*. Also, as this is C++ and not C, you're better served by something like std::copy which won't break your code subtly if charMap someday becomes a complex type. On the same note, prefer std::string instead of const char* in most situations.
Your use of sizeof() is wrong when calling new. You are allocating an array of CharMapT elements. You have to specify the number of elements, but you are specifying a byte count instead. So you need to fix that:
structList = new CharMapT[sizeof(list) / sizeof(CharMapT)];
With that fixed, the result of the memcpy() will be that structList will contains an exact copy of the raw data that list[] contains. That means that the structList[N].name pointers will contain the same values as the list[N].name pointers, and thus they will all be pointing at the same physical memory for the string values.
If you want to do a deep copy of the string values, you have to allocate them separately, eg:
void ABC::Function ()
{
CharMapT list[] =
{
{"NAME1", 1},
{"NAME2", 2},
{"NAME3", 3}
};
int num = sizeof(list) / sizeof(CharMapT);
structList = new CharMapT[num];
for (int i = 0; i < num; ++i)
{
int len = strlen(list[i].name);
structList[i].name = new char[len+1];
strcpy(structList[i].name, list[i].name);
structList[i].name[len] = 0;
structList[i].id = list[i].id;
}
...
for (int i = 0; i < num; ++i)
delete[] structList[i].name;
delete[] structList;
}
I'd like to add to #EdS.'s answer:
Your code is just much more c++ than c-style c++ code if you do it like this:
#include<string>
#include<vector>
struct CharMap
{
CharMap(const std::string& name, unsigned char id); // only needed if you don't use -std=c++11
std::string name;
unsigned char id;
};
CharMap::CharMap(const std::string& name, unsigned char id):
name(name),
id(id)
{}
class ABC
{
public:
ABC(); // or ABC() = default; if you use -std=c++11
void Function();
private:
std::vector<CharMap> structList;
}
ABC::ABC(){} // not needed with -std=c++11
void ABC::Function ()
{
// This works with -std=c++11:
//structList =
//{
// {"NAME1", 1},
// {"NAME2", 2},
// {"NAME3", 3}
//};
// without c++11:
structList = std::vector<CharMap>(3);
structList[0] = CharMap("NAME1",1); // don't worry about copies, we have RVO (check wikipedia or SO)
structList[1] = CharMap("NAME2",2);
structList[2] = CharMap("NAME2",3);
}
Why not using std::vector for making an array? You can do that like this:
#include<vector>
std::vector<CharMapT> structList(list.size());
It is safer, too, avoiding using pointers decreases the chance of memory leaks or bugs arising due to wrongly using the sizeof operator.
I suppose you do not really want a structList, that has as many elements as the memory size of your list. (If list is double this could be many times more than the number of elements in your list.)
Also, memcpy is really not necessary, if list is also a vector (that is a c function really). You just do a simple assign operation:
structList = list; // given that list is a vector.
This will copy the elements like memcpy.