Hey guys! When I try to do the following in a header file
static const char FOOT[] = "Foot";
static const char FEET[] = FOOT;
I get a compiler error of error: initializer fails to determine size of FEET. I was wondering what the cause of this is, and if there is a way to rectify it. Thanks!
Even though why you get this error has been answered, there's more to the story. If you really need for FEET to be an array, then you can make it a reference instead of a pointer:
char const foot[] = "foot";
char const (&feet)[sizeof foot] = foot;
// reference to array (length 5) of constant char
// (read the declarations "from the inside-out")
char const* const smelly_feet = foot;
// constant pointer to const char
int main() {
cout << sizeof feet << ' ' << feet << '\n';
cout << sizeof smelly_feet << ' ' << smelly_feet << '\n';
cout << sizeof(void*) << " - compare to the above size\n";
return 0;
}
(More examples of the inside-out rule.)
Secondly, static at file and namespace scope means internal linkage; so when you use it in a header, you'll get duplicate objects in every TU using that header. There are cases when you want this, but I see no reason for it in your code, and it's a common error.
Regarding array size: The sizeof operator returns the memory-size of an object or instance of a type. For arrays this means the total memory-size of all of its items. Since C++ guarantees that sizeof(char) is 1, the memory-size of a char array is the same as its length. For other array types, you can divide by the memory-size of one item to get the length of an array:
void f() {
int array[5];
assert((sizeof array / sizeof *array) == 5);
}
And you can generalize it to a function template:
template<class T, int N>
int len(T (&)[N]) {
return N;
}
// use std::size_t instead of int if you prefer
This exists in boost as boost::size.
You may see code that uses sizeof array / sizeof *array, either through a macro or directly, either because it's old or doesn't want to complicate matters.
The cause is that you are saying that FEET[] is an array of chars but you're initializing it to a ptr;
To rectify, you can change FEET from FEET[] to *FEET
Could also do the same with FOOT
There is no '=' operator for arrays in C++, you need to use strcpy or something similar (which you can't do with a static const). Depending on your requirements the following might be useful:
#define contentsOfFoot "FOOT"
static const char FOOT[5] = contentsOfFoot;
static const char FEET[5] = contentsOfFoot;
static const char *feeet = FOOT;
static is deprecated, and const variables at namespace scope are effectively static, anyway. Also, please reserve ALL_CAPS for preprocessor identifiers.
A bigger question is why you are using raw arrays at all. You very likely want something more like this:
std::string const foot = "foot";
std::string const feet = foot;
Or, more likely:
#include <string>
namespace spbots {
typedef std::string string_t;
string_t const foot = "foot";
string_t const feet = foot;
}
One way would be this
static const char FOOT[] = "Foot";
static const char *FEET = FOOT;
I want to emphasise that you shouldn't put that stuff in a header file. Variables should only be put in header files if you want to make them globally visible (generally not a great idea but it's a legitimate technique).
feet.h
extern char feet[];
feet.cpp
char feet[] = "FEET";
Now when you include feet.h in a different .cpp file, say leg.cpp, the declaration in feet.h means leg.cpp can see and use the array defined in feet.cpp
The extern keyword has the opposite meaning to the static keyword you use. A typical use of static is as follows;
feet.cpp
static char feet[] = "FEET";
Now feet[] is explicitly not visible outside feet.cpp. The static keyword is responsible for this lack of visibility. So static=local, extern=global and (perhaps unfortunately?) extern is the default, so if you don't use either keyword you get extern whether you like it or not.
Because static=local, there's nothing to communicate to other modules, so no need to have a declaration in a header file for other modules to see. Everything is kept within feet.cpp, probably a better idea than a global variable.
Another point I am implicitly trying to get through with this explanation is that declarations go into header files, definitions go into .cpp files. In your question you have a definition in a header file. Not illegal, but if you include it in more than one file (and if you don't, why would you put it in a header?), you will get a single variable defined multiple times, which will give you a link error.
All of this is actually old school C rather than C++ in the modern sense of the word. In other words you are really writing C, but since C is (almost) a subset of C++, you can still use C++ to do this stuff.
Related
I have a file which contains arrays of strings representing some icons.
static constexpr char icons1[2][40] = {
"icon1_A", "icon1_B"
};
static constexpr char icons2[3][30] = {
"icon22_A", "icon2_B", "icons2_C"
};
Then I have a class that wants to be initialized with a reference to these icons.
class Display {
public:
Display(const char ** _icons) : icons(_icons), current_icon(0) {}
void print_next_icon() {
std::cout << icons[++current_icon] << std::endl;
}
private:
const char **icons;
size_t current_icon;
}
I am getting a compiler error when I try to initialize the Display class by passing it the constexpr icons:
Display i1(icons1);
Display i2(icons2);
I've tried casting it to const char**, but the compiler complains that the cast removes attributes.
The declaration here is needlessly complicated. Try and keep it simple:
static const char* icons1[] = {
"icon1_A", "icon1_B"
};
If you're passing these in as arguments and you need to know exactly how many there are it helps to have some kind of terminator:
static const char* icons1[] = {
"icon1_A", "icon1_B", nullptr
};
Where you can iterate through this list until you hit nullptr and then stop.
constexpr is used for, not surprisingly, const expressions, as in more complex expressions with operators in them and/or functions that you want to evaluate. It's not necessary here since nothing exotic is going on, this is a straight-forward const declaration.
What's worth noting here is that the memory layout of char** and char[3][40] are completely different. In the first case you have an array of pointers, where those pointers refer to arbitrary memory locations, and in the second you have what is effectively a contiguous chunk of 120 bytes, no pointers at all. This cannot be recast to the other form, it requires creating a new array of pointers.
That being said, your function assumes that these pointers will have an indefinite lifespan, which can be risky. It's almost always safer to use std::string, as in std::vector<std::string> to pass these around.
How to add some element to globally declared char array & access the elements of the array from the another function?
I declared like this in source file
extern char *ArrayItems[] = {"Item1"};
Function 1 - Add element into Array
void AddSomeElementToGloablArray()
{
ArrayItems[1] = "Item 2";
ArrayItems[2] = "Item 3";
...
}
Function 2 - Add again some element into Array
void AddSomeElementToGloablArray()
{
ArrayItems[3] = "Item 3";
ArrayItems[4] = "Item 4";
...
}
Main Function - To access the element of the array
void Main()
{
AddSomeElementToGloablArray();
char *ItemValue = ArrayItems[3];
}
I tried like above code but it does not return added element. Here I cannot pass or return an array from function.
Please anybody help
How to add an element to Global char *Array[]?
There is no way to add an element to an array. During the life time of an array its size never changes - no elements are ever added nor removed.
The way to solve this is indirection: Instead of a plain static/automatic array, we use a pointer to one and allocate that array dynamically. When you want more elements, we simply create a new, bigger array, copy (possibly by moving) the old elements into the new one and destroy the old array. This data structure is typically named "growable array" or "resizable array".
Of course, it would be madness to maintain bare pointers to a dynamic array, so we want to create a RAII wrapper class, with proper destructor etc. to make sure that the memory is handled properly. At this point I'm going to point out that such wrapper for a resizable array exists in the standard library, so there is no need for you to implement one yourself: std::vector.
extern char *ArrayItems[] = {"Item1"};
This is ill-formed because a string literal can not be converted to a (non-const) char*.
ArrayItems[1] = "Item 2";
This has undefined behaviour because the index is outside the bounds of the array.
extern char *ArrayItems[] = {"Item1"};
I'm not sure if extern is needed here. If you only use it in a single source file, you don't need the extern. If you need to share the variable across multiple compilation units (source files), you should declare it in header file with extern keyword, and then declare the variable itself in any one of the source files.
/* shared.h */
extern char *ArrayItems[];
/* foo.c */
char *ArrayItems[] = {"Item1"};
Now, to add an element to array is not trivial. You need to do dynamic memory allocation. If you are using C++, it is highly recommended that you use std::vector instead. The following code works in standard compiler that support C++11.
#include <vector>
#include <iostream>
std::vector<char const *> ArrayItems = {"Item1"};
void AddSomething()
{
ArrayItems.push_back("Foo");
ArrayItems.push_back("Bar");
}
int main()
{
std::cout << ArrayItems[0] << std::endl;
AddSomething();
std::cout << ArrayItems[1] << std::endl;
std::cout << ArrayItems[2] << std::endl;
return 0;
}
Output:
Item1
Foo
Bar
I use char const * instead of char * because "Item1" is a string literal, which shall not be modified on runtime anyway.
short answer: don't do that. use std::vector and call vector.push_back.
long answer: a global array declared with [] has fixed width, so you cannot just create a new member by accessing it's element number, this is extremely dangerous as you are accessing out of bounds memory.
extern keyword does not allocate any memory for ArrayItems. It is only a declaration and not a definition. If this variable is declared in some other file in your project, and you want to use in the current file, you need to declare with extern keyword. If this variable is not defined in any other file, you can simply remove that keyword. Your code will work. However as suggested in the other answers, it is not a good idea to use global variables.
This code will not compile:
#ifndef RemoteControl_h
#define RemoteControl_h
#include "Arduino.h"
class RemoteControl
{
public:
RemoteControl();
~RemoteControl();
static void prev_track();
static void next_track();
static void play_pause_track();
static void mute();
static void vol_up();
static void vol_down();
void respond(int code);
void add_code(int code, void (*func)());
private:
boolean active = true;
struct pair {
int _code;
void (*_func)();
};
const int max = 1000;
int database_length = 0;
pair database[max]; //This line doesn't compile unless I use a literal constant instead of "max"
};
#endif
But if I put the section below in the constructor for the class instead it works fine.
const int max = 1000;
int database_length = 0;
pair database[max];
Am I not allowed to declare an array within a class in c++ and use a virtual constant as the length? I am working in arduino if that makes a difference, but I expect that I am not understanding something with the c++ language since this is a standard .h file. Oh and the problem isn't the .cpp file because I completely removed it with the same results: compiles with literal constant length but not virtual constant length.
In C or C++,try using malloc() in stdlib.h, cstdlib for c++. Don't forget free()
const int max = 1000;
struct pair *ptr = malloc(sizeof(pair) * max); // allocated 1000 pairs
free(ptr); // when the amount of memory is not needed anymore
Let me first clear a few things up for you.
In C, a const variable is considered as const-qualified, it is not a compile-time constant value (unlike an integer literal, which is a compile time constant value). So, as per the rules for normal array size specification, you cannot even use a const variable in this case.
In C, we may have the provision to use VLA which enables us to use syntax like pair database[max] even if max is not a const variable but that is again some optional feature of the compiler (as per C11).
In C++, we can use a const variable as the size of array, as in C++, a const variable is a compile time constant.
So, to answer your question:
In C, your code will be ok if your compiler supports VLA. and even if max is not const.
In C++, there is no VLA, but it maybe supported as a gnu extension. If max is const, it will be ok.
The easiest fix is to just take the
const int max = 1000;
out of the class and put it above the class.
Even better would be to ensure that it is a compile-time constant like so:
constexpr int max = 1000;
Here is a simplified version of what I have (not working):
prog.h:
...
const string c_strExample1 = "ex1";
const string c_strExample2 = "ex2";
const string c_astrExamples[] = {c_strExample1, c_strExample2};
...
prog.cpp:
...
int main()
{
int nLength = c_astrExamples.length();
for (int i = 0; i < nLength; i++)
cout << c_astrExamples[i] << "\n";
return 0;
}
...
When I try to build, I get the following error:
error C2228: left of '.length' must have class/struct/union
The error occurs only when I try to use member functions of the c_astrExamples.
If I replace "c_astrExamples.length()" with the number 2, everything appears to work correctly.
I am able to use the member functions of c_strExample1 and c_strExample2, so I think the behavior arises out of some difference between my use of strings vs arrays of strings.
Is my initialization in prog.h wrong? Do I need something special in prog.cpp?
Arrays in C++ don't have member functions. You should use a collection like vector<string> if you want an object, or compute the length like this:
int nLength = sizeof(c_astrExamples)/sizeof(c_astrExamples[0]);
Just use STL vector of strings instead of array:
#include <string>
#include <vector>
using namespace std;
const string c_strExample1 = "ex1";
const string c_strExample2 = "ex2";
vector<string> c_astrExamples;
c_astrExamples.push_back(c_strExample1);
c_astrExamples.push_back(c_strExample2);
int main()
{
int nLength = c_astrExamples.size();
Arrays in C++ are inherited from C, which wasn't object-oriented. So they aren't objects and don't have member functions. (In that they behave like int, float and the other built-in types.) From that ancestry stem more problems with array, like the fact that they easily (e.g., when passed into a function) decay into a pointer to the first element with no size information left.
The usual advice is to use std::vector instead, which is a dynamically resizable array. However, if you the array size is known at compile-time and you need a constant, then boost's array type (boost::array, if your compiler supports the TR1 standard extensions also available as std::tr1::array, to become std::array in the next version of the C++ standard) is what you want.
Edit 1:
A safe way to get the length of an array in C++ involves an incredible combination of templates, function pointers and even a macro thrown into the mix:
template <typename T, std::size_t N>
char (&array_size_helper(T (&)[N]))[N];
#define ARRAY_SIZE(Array_) (sizeof( array_size_helper(Array_) ))
If you (like me) think this is hilarious, look at boost::array.
Edit 2:
As dribeas said in a comment, if you don't need a compile-time constant, this
template <typename T, std::size_t N>
inline std::size_t array_size(T(&)[N])
{return N;}
is sufficient (and much easier to read and understand).
c_astrExamples is an array, there is no "length()" method in it.
In C++ arrays are not objects and have no methods on it. If you need to get the length of the array you could use the following macro
#define COUNTOF( array ) ( sizeof( array )/sizeof( array[0] ) )
int nLength = COUNTOF(c_astrExamples);
Also, beware of initialisation in a header file. You risk offending the linker.
You should have:
prog.h:
extern const string c_strExample1;
extern const string c_strExample2;
extern const string c_astrExamples[];
I am working on a game and have an interesting question. I have some game-wide constant values that I want to implement in one file. Right now I have something like this:
constants.cpp
extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;
constants.hpp
extern const int BEGINNING_HEALTH;
extern const int BEGINNING_MANA;
And then files just #include "constants.hpp"
This was working great, until I needed to use one of the constants as a template parameter, because externally-linked constants are not valid template parameters.
So my question is, what is the best way to implement these constants? I am afraid that simply putting the constants in a header file will cause them to be defined in each translation unit. And I don't want to use macros.
Thanks
Get rid of the extern and you're set.
This code works perfectly fine in a header, because everything is "truly constant" and therefore has internal linkage:
const int BEGINNING_HEALTH = 10;
const int BEGINNING_MANA = 5;
const char BEGINNING_NAME[] = "Fred";
const char *const BEGINNING_NAME2 = "Barney";
This code cannot safely be put in a header file because each line has external linkage (either explicitly or because of not being truly constant):
extern const int BEGINNING_HEALTH = 10;
extern const int BEGINNING_MANA = 5;
const char *BEGINNING_NAME = "Wilma"; // the characters are const, but the pointer isn't
How about enums?
constants.hpp
enum {
BEGINNING_HEALTH = 10,
BEGINNING_MANA = 5
}
Use "static const int" in your .hpp file, and put nothing in the .cpp file (except whatever other code you have there of course).
make use of namespaces:
namespace GameBeginning {
const int HEALTH = 10;
const int MANA = 5;
};
then u can use as player.health = GameBeginning::HEALTH;
Most compilers simply don't allocate space for const POD values. They optimize them out and treat them as if they had been #defined, don't they?
What ever happened to a simple:
#define BEGINNING_HEALTH 10
Man, those were the days.
Oh wait, those still are the days!
perhaps something along the lines of a static class?
class CONSTANTS {
public:
static inline int getMana() { return 10;};
};
As a quick answer to the title question, a singleton pattern is a possible best, C++ way to define cross-file constants and insure only one instance of the object.
As far as the template parameter problem, you need to pass a type not a value. Your type is "int".