How can I ensure COLOR_NAMES is filled to the correct size at compile-time? If a new color is added, say COLOR_4 (and hence N_COLORS is auto incremented), the compiler will then tell me COLOR_NAMES is not filled to size.
Most answers that I found online is for runtime, not compile time.
This is for C-style notation (no STL and other libraries usage).
enum Colors
{
COLOR_1,
COLOR_2,
COLOR_3,
N_COLORS;
};
const char* COLOR_NAMES[N_COLORS] =
{
/* COLOR_1 */ "Color1",
/* COLOR_2 */ "Color2",
/* COLOR_3 */ "Color3"
};
const char* Blah()
{
Colors color;
...
printf("%s blah blah\n", COLOR_NAMES(color));
}
It is standard practice for such cases of arrays and corresponding enums to compare the "enum size member", N_COLORS in your case, against the number of items in the array.
To get the number of items in an array, simply divide the array size with the size of one array member.
Thus:
_Static_assert(sizeof(COLOR_NAMES)/sizeof(*COLOR_NAMES) == N_COLORS,
"Array item missing!");
Edit:
Oh btw for this to be meaningful the array declaration must be const char* COLOR_NAMES[] = otherwise you wouldn't be able to tell if there are missing initializers in the array initialization list.
The ideal would to be able to use sizeof from preprocessor. But we can't because sizeof is evaluated by the compiler.
There are many ways to bypass this but here is quite simple and portable one:
const char* COLOR_NAMES[] = {
/* COLOR_1 */ "Color1",
/* COLOR_2 */ "Color2",
/* COLOR_3 */ "Color3"
};
typedef char CHECK_COLOR_NAMES[sizeof(COLOR_NAMES) / sizeof(COLOR_NAMES[0]) == N_COLORS ? 1 : -1];
If the test fails, you will attempt to define an array with size -1, which will result into a compilation error.
EDIT: Then we use a typedef to avoid to actually create a variable that we'll not use (Lundin's remark)
with constepxr, you can use :
constexpr static const char* COLOR_NAMES[N_COLORS] =
{
/* COLOR_1 */ "Color1",
/* COLOR_2 */ "Color2",
/* COLOR_3 */ "Color3"
};
static_assert(COLOR_NAMES[N_COLORS-1] !=0);
if you want to use local variable, you can use variant
constexpr variant<const char*> COLOR_NAMES[N_COLORS] =
{
/* COLOR_1 */ "Color1",
/* COLOR_2 */ "Color2",
/* COLOR_3 */ "Color3"
};
static_assert(get<0>(COLOR_NAMES[N_COLORS-1]) !=nullptr);
Related
Briefly, my problem is: I'm building a dynamic memory manager, which contains various different kinds of objects. I'm marking each different kind of object with a tag, and, to make memory debugging easier, I want those tags to appear in memory as four-byte strings of stuff I can read. However, to efficiently switch on those values, I also want to consider them as unsigned 32 bit integers.
Currently the definition of the objects looks like this:
/**
* an object in cons space.
*/
struct cons_space_object {
char tag[TAGLENGTH]; /* the tag (type) of this cell */
uint32_t count; /* the count of the number of references to this cell */
struct cons_pointer access; /* cons pointer to the access control list of this cell */
union {
/* if tag == CONSTAG */
struct cons_payload cons;
/* if tag == FREETAG */
struct free_payload free;
/* if tag == INTEGERTAG */
struct integer_payload integer;
/* if tag == NILTAG; we'll treat the special cell NIL as just a cons */
struct cons_payload nil;
/* if tag == REALTAG */
struct real_payload real;
/* if tag == STRINGTAG */
struct string_payload string;
/* if tag == TRUETAG; we'll treat the special cell T as just a cons */
struct cons_payload t;
} payload;
};
Tags are four character string constants, e.g.:
#define CONSTAG "CONS"
What I want to be able to so is something like
switch ( cell.tag) {
case CONSTAG : dosomethingwithacons( cell);
break;
But of course you can't switch on a string. However, as these are four byte strings, they could be read in memory as 32 bit unsigned ints. What I want is a macro which, given a string as argument, returns an unsigned int. I've tried
/**
* a macro to convert a tag into a number
*/
#define tag2uint(tag) ((uint32_t)*tag)
but what it in fact does is return as a number the ASCII value of the first character at that address - that is,
tag2uint("FREE") => 70
which is the ascii code for 'F'.
Anyone solve this for me? It's twenty years since I wrote anything serious in C.
#define tag2uint(tag) ((uint32_t)*tag)
means "dereference tag (get 'F' in your example), then convert it to uint32_t."
What you want to do should be
#define tag2uint(tag) (*(uint32_t*)tag)
this means "treat tag as pointer to uint32_t, then dereference it."
I have an enum like that:
enum {
ID_FOO = 0,
ID_BAR,
ID_BAZ
}
And a constant array using designated initializers like hat:
char* arr[] = {
[ID_FOO] = "foo stuff",
[ID_BAR] = "bar stuff",
[ID_BAZ] = "baz stuff",
0
}
Now when I add a value to the enum, e.g. after ID_FOO but forget to add it to the array, then I would get an uninitialized null-initialized 'hole' in the array. Is there any way to prevent that, or at least get a warning from the compiler?
A non-portable GCC-only solution is fine.
One way is to add a sentinel maximum value to your enum, which you can use to verify that this maximum value is the same as the number of elements in the array.
enum {
ID_FOO = 0,
ID_BAR,
ID_BAZ,
// insert new values here
ID_MAX
}
assert(ID_MAX == (sizeof(arr)/sizeof(arr[0]) - 1));
This is a runtime check; have a look at C compiler asserts - how to implement? for ideas on how to get a compile-time error instead.
you can use X-Macros to keep them in sync, although some may argue about the prettiness of the resulting code.
The idea is to take all the information you need for both structures and put it into a single macro:
entries.inc
ENTRY(ID_FOO, "foo stuff")
ENTRY(ID_BAR, "bar stuff")
ENTRY(ID_BAZ, "baz stuff")
And then later, redefine your macro such that for each structure you need to build, you pull out the appropriate part from your data:
foo.c
/* here define what entry should be for your enums */
#define ENTRY(id, name) id,
enum {
#include "entries.inc"
};
/* and then redefine for the char array and include again */
#undef ENTRY
#define ENTRY(id, name) [id] = name,
char* arr[] = {
#include "entries.inc"
0
};
int main(int argc, char* argv[]) {
/* whatever */
}
I get the error
subscripted value is neither array nor pointer
when I try to compile my program. I understand it has something to do with the variable not being declared but I checked everything and it seemed to be declared.
static char getValue(LOCATION l)
{
/*return carpark[l.col][l.row]; // Assumes that location is valid. Safe code is
below:
*/
if (isValidLocation(l)) {
return carpark[l.col][l.row]; <<<<<<<< this line
} // returns char if valid (safe)
else {
return '.';
}
Which corresponds to this part of the code in the header
typedef struct
{
/* Rectangular grid of characters representing the position of
all cars in the game. Each car appears precisely once in
the carpark */
char grid[MAXCARPARKSIZE][MAXCARPARKSIZE];
/* The number of rows used in carpark */
int nRows;
/* The number of columns used in carpark */
int nCols;
/* The location of the exit */
LOCATION exit;
} CARPARK;
Carpark was declared in the main prog with:
CARPARK carpark.
Thanks for the help.
carpark is not an array so you probably want something like:
return carpark.grid[l.col][l.row];
The error message is telling you exactly what the problem is. The variable carpark is neither an array nor a pointer, so you cannot apply the [] operator to it.
carpark.grid, however, is an array, so you could write
return carpark.grid[l.col][l.row];
i have a simple structure:
typedef struct {
int test;
} struct1_t;
typedef struct {
struct1_t** tests;
} struct2_t;
struct2_t *str
for(i=0;i<1000;i++) {
(str->tests)[i]=(test1_t *) malloc(sizeof(test1_t));
(str->tests)[i]->test = i;
}
How to know exist str->tests)[i] element on not ?
if (str->tests)[i] != NULL
call Segmentation failed :).
Simply put, you can't. There is no way to know the length of an array in C, you have to keep track of it manually as your array changes or grows.
C arrays are really just blocks of memory, so what you really
want to do as add a field to your structs that keeps track of how
much space has been allocated and make sure you initialize
everything to sane values. You also have to be careful when using
pointers of structs containing to pointers to pointers of structs,
since in your example you failed to properly allocate memory for
everything.
Try this:
typedef struct {
int test;
} test_t;
typedef struct {
test_t* tests; /* We only need a regular pointer here */
size_t numtests; /* This is so we know how many tests we allocated */
} mystruct_t;
/* .... Now skip to the actual usage: */
mystruct_t *str;
int i;
str = malloc(sizeof(mystruct_t)); /* Remember to allocate memory for
the container! */
str->numtests = 1000; /* Set our size inside the container and use it! */
/* Now to allocate an array of tests, we only need to allocate
a single chunk of memory whose size is the number of tests
multiplied by the size of each test: */
str->tests = malloc(sizeof(test_t)*str->numtests);
/* Now let's initialize each test: */
for (i=0; i<str->numtests; i++) { /* Notice we use str->numtests again! */
str->tests[i]->test = 1; /* Notice we don't need all the extra
parenthesese. This is due to the operator
precedence of [] and -> */
}
Now when you need to see if a test element exists, you can just see if the
index is within the size of the container:
if (i >= 0 && i < str->numtests) {
str->tests[i]->test = 2; /* This code only runs if the index would exist. */
}
But that means you have to take care to always initialize str->numtests to be
a sane value. For example, with no allocated tests:
mystruct_t *str = malloc(sizeof(mystruct_t));
/* Initialize the container to sane starting values! */
str->tests = NULL;
str->numtests = 0;
And that's how you know if something exists -- you keep track of it inside
the structures you define. That's because C code maps very directly to
assembly language, and C structs and arrays map very directly to bits and bytes
in computer memory, so if you want to maintain meta information like how
many elements are inside your array, you have to make room for that information
and store it yourself.
It is pretty fundamental that you can't do it this way in C. Your struct2_t would need an extra field such as int no_of_tests, which you would update.
In fact to do what your trying to do there, you also need 2 mallocs -
struct2_t str;
str.tests = malloc( 1000 * sizeof(int) );
str.no_of_tests = 1000;
for(i=0;i<1000;i++) {
str.tests[i] = malloc( sizeof(struct1_t) );
str.tests[1]->test = i;
}
There is nothing in the language to do this for you, you need to keep track yourself. A common solution is to make the last pointer in an arbitrary-size array of pointers be a NULL pointer, so you know to stop looping when you hit NULL.
If your compiler supports _msize you can find out the size that you allocated. For example:
if (i < _msize((str->tests)/sizeof(test1_t))
then i is valid and points to an element of the allocated array
A function I need to use requires a vector argument for return storage with the following signature:
char ***vvar
What am I supposed to pass in there?
How do I access elements afterward?
Let's say you want a function that creates a vector of strings. You might define it and call it like this:
#include "stdio.h"
#include "stdlib.h"
void make_vector(char*** vvar)
{
/* We're going to create a vector of strings. */
char** vector = malloc(sizeof(char*) * 3 );
vector[0] = "Hello";
vector[1] = "world!";
vector[2] = NULL;
/* Now we give the address of our vector to the caller. */
*vvar = vector;
}
int main(void)
{
char** vector_of_strings = NULL;
make_vector(&vector_of_strings);
printf("%s\n", vector_of_strings[0]);
return 0; /* Memory leak is an exercise for the reader. :-) */
}
(In this example it would be simpler to have make_vector return the array, but in a more complex example it's reasonable to pass the address of vector_of_strings.)
I will assume that the vector will contain strings, as that makes the most sense with the signature you describe.
As you also did not give any code, I will assume the function you need to call looks similar to this:
/* This function creates a vector with room for 'length' strings and places it in 'vvar' */
void create_string_vector(int /* in */ length, char*** /* out */ vvar);
As the function expects to be able to change vvar and have that change reflected in the caller, you must pass the address of some variable, so the call should look like
create_string_vector(my_length, &my_var);
That takes care of one level of pointers.
This leaves just the question of how to declare my_var. As it will be a vector, or array, of unknown size, you need to declare it as a pointer. And a string is also a kind of array of unknown size of characters, so you need a pointer for that as well. This leads to the declaration
char* *my_var;
Element access is the easy part: You can treat my_var just as an array:
my_var[0] = "Hello";
This is not a vector by the looks of it.
If the function signature is somethings like function(...,char ***vvar,...), then your solution is not simple.
You need to know how much buffer space you need in each dimension, then create the complicated array as follows:
int dim_1 = 5, dim_2 = 4, dim_3 = 10;
char ***buffer = malloc(sizeof(char**)*dim_1);
for (int i=0;i++;i<dim_1) {
char **buffer_2 = malloc(sizeof(char*)*dim_2);
for (int j=0;j++;j<dim_2) {
char *buffer_3 = malloc(dim_3);
buffer_2[j] = buffer_3;
}
buffer[i] = buffer_2;
}