Is there a way to evaluate a struct variable inside of a conditional statement as a whole such that each element does not need to be written out? For example given the following struct:
typdef struct
{
int a;
int b;
int c;
} number;
number foo = {1, 2, 3};
I would like to evaluate the elements in an if statement such as:
if (foo.a == 1 && foo.b == 2 && foo.c == 3)
{
...
}
However, I want to evaluate the entire struct without having to list individual elements. I know this is not correct but this is along the lines of what I want to accomplish:
if (foo == {1, 2, 3})
{
...
}
Your help is greatly appreciated. Thanks.
You can represent a temporary struct through a compound literal
(number) { 1, 2, 3 }
so a more logical attempt would look as
if (foo == (number) { 1, 2, 3 })
...
but it won't work, since C language does not provide a built-in operator for comparison of struct objects. You can use memcmp instead
if (memcmp(&foo, &(number) { 1, 2, 3 }, sizeof foo) == 0)
...
but unfortunately, this is not guaranteed to work due to unpredictability of the content of any padding bytes your struct objects might have in them.
The best course of action in this case might be to write a comparison function manually
inline bool is_same_number(const number *lhs, const number *rhs)
{
return lhs->a == rhs->a && lhs->b == rhs->b && lhs->c == rhs->c;
}
and then use it in combination with compound literal feature
if (is_same_number(&foo, &(number) { 1, 2, 3 }))
...
Not sure you need a struct but either way just cast to unsigned char * and use a literal where 0x000000010002 would be the format of the literal representing 3 integers {0 1 2}.
To avoid issues with endianess just declare the integral as a value at runtime and then the representation will match the system endian.
You could also use a macro if run time definition was not allowed.
I wouldn't waste the memcpy.
Related
I want to create a large number of declarations of static arrays, each with a different (static) size. I also want to be able to create an instance of all of them, and access them easily just with their ID. Can this be done with macros in C ?
i.e. I want to shorten this code
int array_1[SIZE_1];
int array_2[SIZE_2];
int array_3[SIZE_3];
int array_4[SIZE_4];
int array_5[SIZE_5];
int array_6[SIZE_6];
.
.
.
int array_40[SIZE_40];
and create this code (where the parts between <> are the ones I hope macros can do for me).
int StoreInArray(int array_id, int position, int value)
{
if(position < SIZE_<array_id>)
{
array_<array_id>[position] = value;
return 0;
}
else
{
return 1;
}
}
Of note : memory imprint is important. I really want to have each array be exactly the size that it must be, and no more - unless a cheap solution is offered.
The correct solution is likely to reconsider your overall program design and instead do something like this:
typedef struct
{
int* data;
size_t size;
} array_t;
const array_t array [40] =
{
{ some_array, 3 },
{ some_other_array, 5 },
...
};
A much worse idea is to implement an evil macro. It might look like this:
// NOT RECOMMENDED
#define StoreInArray(id,pos,val) (pos < SIZE_##id ? (array_##id[pos] = val,1) : 0)
Where the parameter id is an integer constant such as 1. Token concatenation then forms SIZE_1, array_1 etc as the macro is expanded.
This is written as a function-like macro only assigning to the array if pos is smaller than the array size. If so, the macro returns 1 otherwise 0. The comma operator is used inside the conditional operator ?: to achieve this.
Example:
#include <stdio.h>
#define SIZE_1 4
#define SIZE_2 2
#define SIZE_3 5
int array_1[SIZE_1];
int array_2[SIZE_2];
int array_3[SIZE_3];
#define StoreInArray(id,pos,val) (pos < SIZE_##id ? (array_##id[pos] = val,1) : 0)
int main(void)
{
if(StoreInArray(1, 3, 123))
{
printf("%d\n", array_1[3]); // prints 123
}
if(StoreInArray(1, 4, 123))
{
printf("%d\n", array_1[3]); // doesn't get executed
}
if(StoreInArray(3, 4, 456))
{
printf("%d\n", array_3[4]); // prints 456
}
}
I'm not quite into enums, but I need to create a datatype in C that represents numbers with just one digit.
I have tried with enums like:
enum digit {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Obiously the compiler interpret this as assigning the enumeration to a non-specified value.
Is there any way to "cheat" the compiler to let me do this?
Is there any other possible way to bound the range of an integer?
HAL2000's answer is good, still I will elaborate on it. As discussed in the comments, assert() is only the correct way if the setter is expected to be always called with a number between 0 and 9 and failure to do so is considered a programming error.
If you want validation instead (only set the value when it's in the correct range, otherwise report an error to the calling code), you'd change the setter like this:
static inline int
digit_set(struct digit *d, unsigned int val)
{
if (val > 9) return -1;
d->value = val;
return 0;
}
You can pick the returned values freely, -1 for error and 0 for success is very widespread in C, so I picked this. You could also prefer 1 for success and 0 for error, which would make your return value directly usable in a boolean expression.
This whole idea has a little weakness: Nothing will ever prevent you from directly setting the value member, bypassing your setter. Now, there's a solution to this as well, but it comes with costs. You can hide the definition of the struct in a separate translation unit, therefore calling code doesn't ever see its internals. It could look like this:
digit.h:
#ifndef DIGIT_H
#define DIGIT_H
typedef struct Digit Digit;
Digit *Digit_create(int val);
int Digit_setVal(Digit *self, int val);
int Digit_val(const Digit *self);
void Digit_destroy(Digit *self);
#endif
dgit.c:
#include <stdlib.h>
#include "digit.h"
struct Digit {
int val;
};
Digit *Digit_create(int val)
{
if (val < 0 || val > 9) return 0;
Digit *self = malloc(sizeof *self);
if (!self) return 0;
self->val = val;
return self;
}
int Digit_setVal(Digit *self, int val)
{
if (val < 0 || val > 9) return -1;
self->val = val;
return 0;
}
int Digit_val(const Digit *self)
{
return self->val;
}
void Digit_destroy(Digit *self)
{
free(self);
}
The cost:
This way of information hiding unfortunately requires a separate translation unit and dynamic allocation of the objects, which is expensive. I personally wouldn't recommend it for such a simple thing. But if you're e.g. writing a library and want to enforce it can't be used in a wrong way, it's worth a thought.
This basically is OOP realized in C, and for more complex structures, it really gives some benefit (also in structuring your program).
In the example above, the "constructor" Digit_create() makes sure to only ever construct valid objects. This is generally a good idea for robust code in more complex scenarios.
If you decide to implement something like this, make sure the deallocation function (here Digit_destroy()) works the same way as free(): It should silently ignore a null pointer. This is trivial here, because there's nothing else to do than calling free().
I recomend to use an abstract datatype with setters and getters if you really have to use range checking (otherwise use char/int and make sure not to write buggy code):
/* digit.h */
#include <assert.h>
struct digit
{
unsigned int value;
};
static inline unsigned int
digit_set(struct digit *d, unsigned int val)
{
assert(val <= 9);
d->val = val;
return val;
}
static inline unsigned int
digit_get(const struct digit *d)
{
return d->val;
}
You can't limit the range of values for either a type or variable in C unfortunately.
I would do a typedef char digit or typedef int digit and use that as the type for your variables, being sure not to assign anything besides 0 to 9 to your value. Note that this will not do any typechecking, and merely serves as documentation for you.
I'm trying to create an RPG-esque inventory, my inventory contains a type 'sword' which is an array.
Here's the code for my sword struct:
typedef struct
{
char weaponName[35];
int damage;
int rarity;
float price;
} sword;
Here's the one for the inventory:
typedef struct
{
sword SwordInvent[size];
} inventory;
I tried to initialize the SwordInvent array in the main function but it ends up with an error.
[Error] expected expression before '{' token
main()
{
inventory inv;
inv.SwordInvent[0] = {"Paper Sword", 1, 1, 1};
}
Can anyone be kind enough to help me get out of this hole? :(
EDIT
I could not thank you all enough! I wasn't really expecting to get this much of help! Seriously, thank you!
You can't just start listing stuff inside braces and have the compiler magically figure out what you want. It doesn't work like that, except with initializers. Initializers, e.g.
const sword excalibur = { "Excalibur!", INT_MAX, INT_MAX, FLT_MAX };
are different from assignment. With initializers, it's assumed that the right-hand side is going to match the left-hand side, since it's an initializer. Also, they existed longbefore compound literals, so way back this was all you could to with = and structures.
Your code (assignment) is a bit like this:
float x;
x = 1 / 2;
This does not do a floating-point division, since 1 and 2 are both integers; the compiler does not figure out that this should have a floating point result based on the type of the left-hand side (and no, with an initializer for a float it still doesn't help, float x = 1 / 2; will not assign 0.5 but 0; end of analogy).
The same is true (kind of) for your brace-list assignment. There needs to be something on the right hand side that indicates the type of the braced list.
Thus, you need to use the compound literal syntax:
inv.SwordInvent[0] = (sword) {"Paper Sword",1,1,1};
Also, your sword is not an array, it's a struct.
When you write:
inventory inv;
inv.SwordInvent[0]={"Paper Sword",1,1,1};
you are not doing initialization; you are doing (attempting to do) an assignment. Initialization would look like:
inventory inv = { { "Paper Sword", 1, 1, 1 } };
Also note that this initializes all elements of the inv variable; the ones without an explicit value are zeroed.
If you want to do assignment, use a compound literal (C99 or later):
inventory inv;
inv.SwordInvent[0] = (sword){ "Paper Sword", 1, 1, 1 };
Note that after this executes, only element 0 of the array has values assigned; all the other elements are still uninitialized (have indeterminate values). So, unless size == 1, there's a fairly big difference between the initialization and the assignment.
You have to specify the type before assignment:
inv.SwordInvent[0] = (sword) { "Paper Sword", 1, 1, 1 };
You can do it at the declaration line.
The simplest way to emulate what you're trying to do is:
inventory inv = {{"Paper Sword",1,1,1}};
A more general (and perhaps readable) manner would be:
inventory inv =
{
.SwordInvent =
{
{
.weaponName = "Paper Sword",
.damage = 1,
.rarity = 1,
.price = 1
}
}
};
If you want to initialize, say, two entries in the array, then you could use something like:
inventory inv =
{
.SwordInvent =
{
{
.weaponName = "Paper Sword",
.damage = 1,
.rarity = 1,
.price = 1
},
{
.weaponName = "Light Saber",
.damage = 100,
.rarity = 100,
.price = 100
}
}
};
inv.SwordInvent[0]={"Paper Sword",1,1,1};
Such assignment is illegal. Expression at the right side of = should have proper type. The easiest way is to use compound literal (as mentioned in other answers):
inv.SwordInvent[0] = (sword){"Paper Sword",1,1,1};
Alternatively you can use next initialization:
inventory inv = {
{
{"Paper Sword",1,1,1}, /* init SwordInvent[0] */
{"Paper Sword",1,1,1}, /* init SwordInvent[1] */
/* ... */
}
};
This variant conforms to C89, that may be useful if your compiler doesn't support newest language features.
When doing embedded programming with C, many times I find myself doing maps with enum and array because they are fast and memory efficient.
enum {
ID_DOG = 0,
ID_SPIDER,
ID_WORM,
ID_COUNT
};
int const NumberOfEyes[ID_COUNT] = {
2,
8,
0
};
Problem is that sometimes when adding/removing items, I make mistake and enum and array go out of sync. If initializer list is too long, compiler will detect it, but not other way around.
So is there reliable and portable compile time check that initializer list matches the length of the array?
This is possibly a situation where X macros could be applied.
animals.x
X(DOG, 2)
X(SPIDER, 8)
X(WORM, 0)
foo.c
enum {
#define X(a,b) ID_##a,
#include "animals.x"
#undef X
};
int const numberOfEyes[] = {
#define X(a,b) b,
#include "animals.x"
#undef X
};
This not only guarantees that the lengths match, but also that the orders are always kept in sync.
What about a compile time assertion like the following? (Yes, there are more elaborate CT_ASSERT macros; this is to illustrate the idea.)
#define CT_ASSERT(expr, name) typedef char name[(expr)?1:-1]
enum {
ID_DOG = 0,
ID_SPIDER,
ID_WORM,
ID_COUNT
};
int const NumberOfEyes[] = {
2,
8,
0
};
CT_ASSERT (sizeof NumberOfEyes/sizeof *NumberOfEyes == ID_COUNT, foo);
Now when the NumberOfEyes array has more or less elements than ID_COUNT, this will cause an error along x.c:15: error: size of array 'foo' is negative. Negative array dimensions are a constraint violation that must be diagnosed by any C compiler out there.
When declaring a const table, it is possible to get the size of the table using sizeof. However,
once you stop using the symbol name, it does not work anymore. is there a way to have the following program output the correct size for table A, instead of 0 ?
#include <stdio.h>
struct mystruct {
int a;
short b;
};
const struct mystruct tableA[] ={
{
.a = 1,
.b = 2,
},
{
.a = 2,
.b = 2,
},
{
.a = 3,
.b = 2,
},
};
const struct mystruct tableB[] ={
{
.a = 1,
.b = 2,
},
{
.a = 2,
.b = 2,
},
};
int main(int argc, char * argv[]) {
int tbl_sz;
const struct mystruct * table;
table = tableA;
tbl_sz = sizeof(table)/sizeof(struct mystruct);
printf("size of table A : %d\n", tbl_sz);
table = tableB;
tbl_sz = sizeof(tableB)/sizeof(struct mystruct);
printf("size of table B : %d\n", tbl_sz);
return 0;
}
Output is :
size of table A : 0
size of table B : 2
This is the intended behavior of sizeof. But is there a way for a compiler to know the size of a const table, given a pointer to the table instead of the symbol name ?
you are asking for the sizeof a pointer. That is always the pointer size (ie usually 4 bytes on a 32-bit machine and 8 bytes on a 64-bit machine). In the 2nd attempt you are asking for the sizeof the array and hence you get the result you'd expect.
Is there a way for a compiler to know the size of a const table, given a pointer to the table instead of the symbol name?
No, because sizeof() is evaluated at compile-time (unless it is a VLA, but a VLA is not a constant table), and the compiler cannot, in general, tell which table the pointer is pointing to. Granted, in the scenario shown, it might be possible in some hypothetical variation of the C language, but that would mean varying definitions of what sizeof() returns, which would be a bigger problem than not getting the answer you might like but do not get.
So, as everyone else ably pointed out, when you take the size of a pointer, you get the size of the pointer. Assuming a standard 32-bit machine since the results are consistent with that assumption, your structure is 8 bytes and your pointers are 4 bytes, so the result of the division is zero, as expected.
No - you're asking for the sizeof() a pointer. But since what you're really trying to get is the number of elements in an array, you can use a macro that will return that value but will generally give you an error if you pass a pointer instead of an array:
#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
See this SO answer for more details: Is there a standard function in C that would return the length of an array?
For an even safer solution when using C++ instead of C, see this SO answer that uses templates to ensure that trying to get an array count on a pointer will always generate an error: Compile time sizeof_array without using a macro
Short answer is no; if all you have is a pointer, then there's no (standard) way to get the size of the thing being pointed to through that pointer.
Although syntactically correct, your sample is more conventionally written as:
const struct mystruct tableA[] = {
{1, 2},
{2, 2},
{3, 3},
};
Which is less verbose and therefore more readable.