c++ - Defining const variable not working across header file - c++

I am currently working on a little program for the Raspberry Pi. It involves some 7 segment displays. To be able to write more programs for this display I decided to extract the code that directly communicates with the GPIO's to a seperate .cpp and .h file.
Since the number of digits is variable I used a variable for that. The digits themselves are stored in a array consiting out of 8 bit integers.
This is what my setup looks like:
7_segment.h:
extern const uint8_t numDigits;
extern uint8_t digits[];
7_segment.cpp:
#include "7_Segment.h"
uint8_t digits[numDigits] = {0x00}; // Line 7
And the file with the "actual" program:
clock.cpp:
#include "7_Segment.h"
const uint8_t numDigits = 4;
When I execute
g++ clock.cpp 7_segment.cpp -o clock -std=c++0x -lwiringPi
I get this output:
7_segment.cpp:7:27: error: array bound is not an integer constant before ‘]’ token
What can I do to resolve this?

The numDigits=4 is defined in the clock.cpp. The 7_segment.cpp has no idea about the size of array digits[]. Array sizes need to be compile-time constants, so you'll need to put the actual number in 7_segment.cpp or as a compile-time constant in 7_segment.h instead.

Related

C++ error: fields must have a constant size

can someone please give me a hint how to solve the following problem:
clang++-7 -pthread -std=c++17 -o main createLibrary/configuration.cpp createLibrary/growbox.cpp createLibrary/helper.cpp createLibrary/httprequests.cpp main.cpp
In file included from createLibrary/configuration.cpp:2:
In file included from createLibrary/configuration.h:1:
In file included from createLibrary/growbox.h:12:
createLibrary/httprequests.h:13:10: error: fields must have a constant size:
'variable length array in structure' extension will never be supported
char device[configuration::maxNameSize];
^
1 error generated.
I'm including the .h files in the order configuration.h, httprequests.h. I want all necessary config-parameters to be configured in the configuration.cpp file, but I got the displayed error. What am I doing wrong here?
configuration.h
extern int const maxNameSize;
configuration.cpp
int const configuration::maxNameSize = 30;
httprequests.h
char device[configuration::maxNameSize];
httprequests.cpp
char HTTPREQUESTS::device[configuration::maxNameSize];
An extern const int is not a constant expression.
a variable is usable in constant expressions at a point P if
the variable is
a constexpr variable, or
it is a constant-initialized variable
of reference type or
of const-qualified integral or enumeration type
and the definition of the variable is reachable from P
and
P is in the same translation unit as the definition of the variable
(emphasis added)
I want all necessary config-parameters to be configured in the
configuration.cpp file
You are out of luck. The value of maxNameSize must be visible to it's compile-time users.
Declare maxNameSize like this
// configuration.h
class configuration
{
public:
static const int maxNameSize = 30;
...
};
And no need to define it in configuration.cpp.
Your way doesn't make maxNamesize a compile time constant.
EDIT, I am assuming that configuration is a class. If it's a namespace then do the following instead
// configuration.h
namespace configuration
{
const int maxNamesize = 30;
...
}
Constants are an exception to the one definition rule, so it's OK to define them in a header file.
What am I doing wrong here?
You have defined an array variable with size that is not compile time constant.
Solution: You can either
Define the variable in the same translation unit where you use it as the size of an array so that it may be compile time constant. Given that the array is in a header, which presumably is included into multiple translation units, the size cannot be defined externally. It has to be either static or inline.
Or use a dynamic array instead. Simplest way to create dynamic array is to use std::vector.

What Should go in my Header File in C++?

I'm just getting started on my first ever C++ program and am pretty much just learning as I go. The program is supposed to have 3 different files, a header file (prog1.h), a prog1.cpp file (not sure the right terminology for this one) and a test file that includes main: to test our program (prog1_test.cpp).
Not asking for help on any of this (yet, I'm sure I'll be posting another question once I get into it), but figured you'd need to know what the program is supposed to do in order to understand my question. Our program is supposed to read in some numbers from a file and put these numbers into a 2D array. It's then supposed to assign characters to each number value and print the current array and the "picture" created with the characters. Then it will go through the array, making sure that each number doesn't differ in value from it's neighbors by more than 1, if it does, the program is to replace that number with the average of its neighboring values. The program will then print out this corrected array and "picture" created with the characters assigned to the corrected array.
I know that header files are supposed to include code that will be used across multiple files, but am having trouble figuring out what parts of my program need to go in this file. For example, would my code to open, read, and close the data file be included here, or no since the file is only being opened, read, and closed once?
Header files contain function and class declarations. These simply declare the name of the function, its return type, and its argument list. The .cpp file contains the definitions of these functions -- i.e. the actual implementation. The header file is visible to the rest of the program if you #include it in other files, but the implementation details are hidden in the .cpp file.
Anything declared/defined in the .cpp file that is not in the .h file is not visible to the rest of the program, so you can define internal variables, helper functions, etc. in the .cpp file and those implementation details will not be visible. An example of this is foo() in my example below.
A very rough sketch of your program would look like this:
In prog1.h:
#include <iostream> // and whatever other libraries you need to include
#define ARRAY_SIZE 100 // and other defines
// Function declarations
// Read number from file, return int
void read_number(int array[ARRAY_SIZE][ARRAY_SIZE]);
char assign_char(int n);
void print_array(int array[ARRAY_SIZE][ARRAY_SIZE]);
void neighbor_check(int array[ARRAY_SIZE][ARRAY_SIZE]);
In prog1.cpp:
// included headers, defines, and functions declared in prog1.h are visible
#include "prog1.h"
void read_number(int array[ARRAY_SIZE][ARRAY_SIZE]) {
// implementation here
}
char assign_char(int n) {
char c;
// implementation here
return c;
}
void print_array(int array[ARRAY_SIZE][ARRAY_SIZE]) {
// implementation here
}
void neighbor_check(int array[ARRAY_SIZE][ARRAY_SIZE]) {
// implementation here
}
// not visible to anything that #includes prog1.h
// since it is not declared in prog1.h
void foo() {
// implementation here
}
In prog1_test.cpp:
// included headers, defines, and functions declared in prog1.h are visible
#include "prog1.h"
// any other includes needed by main()
int main() {
int array[ARRAY_SIZE][ARRAY_SIZE];
read_number(array);
for (int i = 0; i < ARRAY_SIZE; i++) {
for (int j = 0; j < ARRAY_SIZE; j++) {
assign_char(array[i][j]);
}
}
neighbor_check(array);
print_array(array);
return 0;
}
The use of various header files, and code/implementation files separate and apart from the application file is done to promote maintainability and reuse of code. By collecting all related functions, variables and data structures in a single file, we prevent having to duplicate that code in every subsequent application we write.
Take for example your situation where you will be developing routines related to matrices or arrays. This scheme allows you to collect the common routines dealing with your arrays into a single file, say arrays.c. Now regardless of how many more programs you write, you have a common file that contain your array routines. Now if you write 5 more applications that need your array routines, you have them ready to go in arrays.c.
For maintainability, let's say you now have a more efficient way of handling input from a file to your array. Instead of having to go back and update the read_array function in 5 different application program files, you simply update the one read_array function in arrays.c and you have accomplished updating that routine for all applications that use it.
How does the header file fit in? In order to use your array functions in other applications, the applications need a common way of including the code to make it available for use. That is done by including your arrays.h header file in each application that needs it. OK, so what goes in arrays.h and what goes in arrays.c? Your header files will include the header files, function declarations, data structures and variables for your array routines that are necessary to implement the function definitions contained in arrays.c. That way any application that wishes to make user of your array routines need only include the line #include "arrays.h" at the beginning of its file to have access to your array functions contained in arrays.c
An example (in C) will help sort things out. Say you have several array functions that read lines in a text file into strings read_array, print the lines prn_array and then frees the memory used by the array and strings free_array. You have collected your array functions in array.c. (we know we will include array.h at the top.) So, for example:
#include "array.h"
char **read_array (char *filename)
{
char *buffer = NULL;
size_t len = 0;
ssize_t read;
char **array = NULL;
int cnt = 0;
FILE *fp;
fp = fopen (filename, "r"); //open file , read only
if (!fp) {
fprintf (stderr, "failed to open file for reading\n");
return NULL;
}
array = calloc (AMAX, sizeof (*array) * AMAX); /* allocate pointers, set NULL */
while ((read = getline (&buffer, &len, fp)) != -1) { /* read each line */
if (cnt == AMAX) {
fprintf (stderr, "Error: AMAX reached\n");
break;
/* you will realloc *array here in real life */
}
if (buffer[read-1] == '\n') { /* strip newline */
buffer[read-1] = 0;
read -= 1;
}
array[cnt] = strdup (buffer); /* copy buffer to array[cnt] */
cnt++; /* increment counter */
}
fclose (fp); /* close file stream (fp) */
return array;
}
void prn_array (char **array)
{
register int j = 0;
while (array[j]) {
printf (" array[%d]: %s\n", j, array[j]);
j++;
}
}
void free_array (char **array)
{
register int j = 0;
while (array[j]) { /* for each allocated string */
free (array[j]); /* free pointer to string */
j++;
}
free (array); /* free array */
}
Now let's create our header. We collect our function declarations along with any variables or data structures used and also include the system headers and any other included header files required by our functions in array.h:
#ifndef MY_ARRAY_H
#define MY_ARRAY_H 1
/* headers required for array.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AMAX 100
/* function declaration */
char **read_array (char *filename);
void prn_array (char **array);
void free_array (char **array);
#endif /* MY_ARRAY_H */
Notice we have wrapped the contents of our header inside a test #ifndef MY_ARRAY_H which just asks the compiler if MY_ARRAY_H is defined yet, ifndef (if not defined), we let the compiler know that everything that follows our #define until we reach the end of the if statement #endif we are defining as MY_ARRAY_H so that if another file tries to include the same header -- the compiler knows it already has it and doesn't need to include it again. (not required, but we also give our define of MY_ARRAY_H the value 1)
So how do we put our custom header array.h and our custom functions for handling arrays in arrays.c to work for us? We write an application that makes use of the functions in arrays.c and to declare all the functions in arrays.c in our application, we simply include array.h in our application. (called application.c below):
#include <stdio.h>
#include "array.h" /* include array.h */
int main (int argc, char *argv[]) {
if (argc < 2) {
printf ("filename.csv please...\n");
return 1;
}
char **my_array = NULL; /* declare pointers */
my_array = read_array (argv[1]); /* call read_array */
prn_array (my_array); /* call prn_array */
free_array (my_array); /* call free_array */
return 0;
}
compile the application.c and array.c files:
gcc -Wall -Wextra -o application application.c array.c
run it on any short text file (less than 100 lines)
$ ./application input.txt
array[0]: 1. This is a simple input file with line numbers
array[1]: 2. for use with application showing the use of
array[2]: 3. header file: array.h
array[3]: 4. array functions defined in: array.c
array[4]: 5. (blank)
array[5]: 6. compiled with the following:
array[6]: 7. gcc -Wall -Wextra -o application application.c array.c
array[7]: 8. --------
array[8]: 9. Now you know!
Now you can see the benefit of creating a separate file holding the related functions, variables, and data structures we will use and creating a header file. We can reuse that code in any application we like simply by including the header file arrays.h in our application. We can update and maintain all our array functions in one place and updating our arrays.c will update all other applications that make use of that code.
I know I have left much out, but make sure you are solid on these concepts. They are fundamental to working with multiple source files and includes in C/C++.
Following basic things should appear in your header file.
class body with function declaration , data variable, constructor
and destructor declaration.
declaration of all functions in
class. Note: not a function body or definition.
inline
functions.
define
all library include header files. so you
need to add only one header file in you respective .c file of this
header file.
structures
ifndef block
forward declaration of
class if you need it some times.
doxygen comments for the
functions and classes and variables.
description of this file as
comment in top of you header file for doxygen.
etc...
Header file should not have any code.

Why Can't I Define Arrays Using Exernal Constants?

I don't quite understand the concepts behind using the extern and const keywords in C++.
I've read a few related questions on the subject ( see below ), but so far I haven't been able to get a grasp on how to use them together.
Related Questions:
How do I share a variable between source files in C? With extern, but how?
What is the Difference Between a Definition and a Declaration?
What is a Translation ( Compilation ) Unit?
What Exactly is the One Definition Rule in C++?
Ok, take for example the following program code:
dConst.hpp
extern const int NUM_GENERATORS; // Number of generators in power plant
extern const int generatorID[NUM_GENERATORS]; // Generator ID numbers
extern const bool generatorStatus[NUM_GENERATORS]; // Generator Status
vConst.cpp
const int NUM_GENERATORS = 4; // Generators in Power Plant
const int generatorID[NUM_GENERATORS] = // Generator ID numbers
{
23, 57, 49, 106
};
const bool generatorStatus[NUM_GENERATORS] = // Production status ( online? )
{
true, false, false, true
};
main.cpp
#include <iostream>
#include "dConst.hpp"
using std::cout;
using std::cin;
using std::endl;
// ----====< M A I N >====----
int main()
{
for ( int iGenerator = 0; iGenerator < NUM_GENERATORS; iGenerator++ )
{
cout << "Generator ";
cout << generatorID[iGenerator];
if ( generatorStatus[iGenerator] )
cout << "is running." << endl;
else
cout << "is offline!" << endl;
}
cout << "Press ENTER to EXIT:";
cin.get(); // Stop
return 0;
}
I am unable to use NUM_GENERATORS to declare my arrays full of generator ID's and statuses. I've included the external definitions at the top: #include "dConst.hpp. From what I've read ( perhaps not closely enough ) on some of the StackOverflow questions here, the compiler and linker should be able to find the values defined in vConst.cpp, and continue on their merry way.
So why aren't they doing this?
The linker can find it, but the compiler can't, since it is in a different compilation unit. The compiler needs to know the size of the array at compile time, but it will only be known at link time if the constant is declared extern.
Mr. Pollex is exactly right, however I thought I might expand on his answer so that folks looking for this information in the future might have a more complete picture. Often modern IDE's obscure the multiple parts involved in converting source code into executable binary.
Broadly speaking the C/C++ compiler only deals with text files (source files). The compiler reads these files, parses them and outputs object files. Object files contain binary executable sections and symbol sections. The linker then runs to 'link' various binary object files into a single executable. It does this by matching the symbols requested with the symbols available.
In the case you have presented you are using the 'extern' keyword to tell the compiler that the value for the defined symbol is defined in a different object than the one generated by this source. This tells the compiler to generate an object that imports this symbol. The linker then takes care of matching up the imported/exported symbols from the objects. Because of this the value you are looking for isn't available when the compiler runs because it depends on an external symbol from another object (that may not have even been build at that point). There is no way for the compiler to know the value of the symbol, therefore it can't use it.

expected constructor, destructor, or type conversion before string constant

I am only in the beginning steps of this program but I like to compile as I am making code. Also I am very new with ADTs so when making this code I ran into some problems that I have no idea what they mean.
Expression.h
#include "header.h" //Library that contains thing like iomanip, cstring, etc.
class Expression
{
private:
char *ieEXP; //Array of characters
char *peEXP; //Array of characters
const int MAX = 40; //Max size for the array
public:
//Initialize both arrays to 0
Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
Expression(const Expression &);
//Destroy contents within the array after program completes
~Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
//void ReadInFix(char *ieEXP);
//void PrintInFix(char *ieEXP);
//void StrCatch();
//bool IsOperator();
//void IntoPostFix(char *peEXP);
//void PrintPostFix(char *peEXP);
//int Priority();
};
Compilation
g++ -c Expression.h
This is the exact error that I get
Expression.h:1: error: expected constructor, destructor,
or type conversion before string constant
Also other methods have not been used yet simply just creating the class right now, and int main has not called anything yet.
Thank you.
The solution is probably to not compile a header file, as g++ doesn't recognize *.h as a source file. You probably want to create a .cpp file that includes your header, and compile that. g++ will recognize the .cpp and treat it properly.
Expression(){ieEXP[MAX] = {0}, peEXP[MAX] = {0}};
ieEXP and peEXP are pointers not arrays.

Class declaration in a header file and static variables

Noob question, but would like to understand the following:
Imagine I have a multifile project. I'm specifying a class in a header file to be shared among all the files in the project, and I write this : static int test = 0; and in the next line this: static const int MAX = 4;
The first one would be an error trying to compile because of the one definition rule. But the second one will compile without errors. Why?
From what I understand, both have the same properties: whole execution storage duration, class scope and no linkage.
Any help?
EDIT: testing an external constant declaration in a header: extern const int MAX = 4; to force external linkage produced the expected error. So I don't understand why with the variable it gives me the error and with the constant it doesn't.
Try
static const int test = 0;
I've sometimes noticed compiler errors with the immediate initialization of static const variables in the header file. You can always use the declaration in the header
class MyClass
{
// ...
static const int test;
// ...
}
and initialize it in the corresponding .cpp file
const int MyClass::test = 0;
This should work properly with any other types than int as well.
Integer constants in C++ don't actually occupy any space in the object and don't act like variables in general. Think about them more like numbers that are given names in this particular context.