How do I validate an enum value read from a file? - c

If I am reading binary values from a file in C, then an integer that is supposed to be a member of an enum can be checked manually by looping through the enum itself and verifying that the integer is one of those values, but this seems like a somewhat tedious process. If I just cast the read value to the enum, then I assume some kind of runtime error will occur if the value is invalid.
Is there a better method of validating the enum than doing a manual check loop?
Note that in my case, the enum(s) in question do not necessarily have consecutive values, so min/max checking is not a solution.

In C, all enums are actually integral types.
So any value of that integral type is a valid value for your enum.
If you are careful and set up the enum labels so they are consecutive (the default is consecutive from 0), it's a simple case of checking if the value from the file is in that range. Otherwise, yes, it's tedious.

enum in C works like an integer, and so it can be forced to any value by any kind of read function taking a pointer, or directly casting it from integer types.
If the enum has only sequential values, some programs have a max enum value for their enum. These can either have explicit values, or have the implicit values which will always start from 0 and go up sequentially. This way they can just check the value is in the allowed range (0 to max - 1), rather than checking it for every allowed value.
typedef enum foo {
foo_a,
foo_b,
foo_c,
foo_max //last
} foo;
int main(void)
{
foo x = (foo)88; // from somewhere
if (x >= 0 && x < foo_max)
printf("valid\n");
else printf("invalid\n");
}

Related

Is It Possible to Limit a Datatype Range in C

My question is about to limit the maximum range of a datatype so as to not exceed it is maximum value.
For example:
unsigned char var1;
In this case minimum value for var1 is 0, maximum value for var1 is 255.
In my case for var1 200-255 are reserved value so it is necessary not to enter these values for safety reasons.
My question, is there any implementation method for C in order to limiting primitive data types range.
Thanks.
The philosophy behind C is that the programmer is in the best position to know whether a range check needs to be performed, and is smart enough to write it if necessary. There is nothing in the standard library that will do this for you.
You can write a simple macro for the test (easier than typing in the actual expression, and it sort of documents exactly what you're doing):
#define RANGE_CHECK(val,lo,hi) ((lo) <= (val) && (val) <= (hi)) // inclusive range check
and invoke it as necessary:
if ( RANGE_CHECK( x, 0, 200 ) )
// do something with x
else
// range violation, handle as necessary.
This is extremely primitive, but should at least point you in the right direction. If you need to do this for floating point, you'll want something way more robust.

c: can typedef-d enum check for the actual values? [duplicate]

The following text is an excerpt from C Programming Language, 2nd Edition, written by the creator of the C language (so I presume it is correct):
Although variables of enum types may be declared, compilers need not check that what you store in such a variable is a valid value for the enumeration.
I have some doubts:
For what cases in the C language doesn't the compiler check the value of an enum?
enum constants are not checked for some reason. Why not? What are the reasons?
Since enum is not checked by the compiler, is using enum error-prone? Please explain.
An enumeration is like a fancy integer, and it's better than defining a whole load of constants or preprocessor macros as names for the constant values you want to store, because a compiler (or editor) can check that you're using the right names and values to go with the right type. On the other hand, being just an int, there's nothing stopping you putting in a value you didn't make a name for, which is occasionally useful.
They can't be checked in every case. What if you add two numbers together to get the value that's going to be put in the enum-typed variable? It could be any value, generated at runtime, so it can't be checked (without a lot of overhead, at least).
Everything in C is unsafe; there's practically no feature which the compiler can totally prevent you from abusing. enums are safe because they are effective at preventing programmer error and confusion, not because they stop you doing something stupid.
You can do a enum like
enum status {
ST_READY = 1 << 0, /* 1 */
ST_WAIT = 1 << 1, /* 2 */
ST_ERROR = 1 << 2, /* 4 */
ST_HALT = 1 << 3, /* 8 */
ST_ETC = 1 << 4, /* 16 */
};
Then define an object of that type
enum status status;
and set it to the bitwise OR of some 'simple' statuses
status = ST_WAIT | ST_ERROR; /* recoverable error */
Note that the value ST_WAIT | ST_ERROR is 6 and that that value is not part of the enum.
To answer your questions:
C compiler lets the programmer shoot himself in the foot.
C compiler lets the programmer shoot himself in the foot.
C compiler lets the programmer shoot himself in the foot.
At what all cases in C language doesn't the compiler check the value of an enum. [edited]
When you assign to it. Assignment from bare integers is allowed, so you can do:
enum E { A, B } x;
x = 10000;
without compiler error. Also, switches in enums are not check for exhaustiveness.
2)Why enum constants are not checked, for some reasons? What are those reasons?
People like to put integers in them. eg.
enum E { END_OF_EVERYTHING = 5 };
where 0-4 are meant as ordinary values, and 5 is kind of special.
Since enum is not checked by the compiler, using enum is error prone?
Yes. Since enums only have values of the least number of bits that can take all enum values, you can get strange results:
enum E { A = 1, B = -1 };
This enum only contains 2 bits of data (values -2, -1, 0, 1). If you assign 10000 into it, strange things may happen (actually seen).

How to insert booleans into a bitfield in C89

As far as I understand, in C89 all boolean expressions are of type integer. This also means that function parameters that represent bool usually get represented by an int parameter.
Now my question is how I can most ideally take such an int and put it into a bitfield so that it only occupies one bit (let's ignore padding for now).
The first thing here is which type to use. Using int or any other unsigned type doesn't work, because when there is only one bit, only -1 and 0 can be represented (at least with two's complement).
While -1 technically evaluates as true, this is not ideal because actually assigning it without undefined behavior can be quite tricky from what I understand.
So an unsigned type should be chosen for the bitfield:
typedef struct bitfield_with_boolean {
unsigned int boolean : 1;
} bitfield_with_boolean;
The next question is then how to assign that bitfield. Just taking an int or similar won't work because the downcast truncates the value so if the lowest bit wasn't set, a value that would previously evaluate to true would now suddenly evaluate to false.
As far as I understand, the boolean operators are guaranteed to always return either 0 or 1. So my idea to solve this problem would be something like this:
#define to_boolean(expression) (!!(expression))
So in order to assign the value I would do:
bitfield_with_boolean to_bitfield(int boolean) {
bitfield_with_boolean bitfield = {to_boolean(boolean)};
return bitfield;
}
Is that correct, and or is there a better way?
NOTE:
I know the problem is completely solved starting with C99 because casting to _Bool is guaranteed to always result in either a 0 or a 1. Where 0 is only the result if the input had a value of 0.
Yes, your solution is correct. However, I wouldn't hide it behind a macro, and I wouldn't name a macro using all_lowercase letters.
!!var is sufficiently idiomatic that I'd say it's fine in code.
Alternatives include var != 0 and, of course, var ? 1 : 0.

Risks of adding uint to enum in function call

I have a function that returns a float number:
float function(enum value)
I then have an enum
typedef enum
{
a = 0,
b,
c
} myenum;
I want to do the following:
function(a+1);
And I wonder if there are any risks other than the risk of unexpected behaviour if the enum changes. My question might seem dumb but I have to make sure that there are no risks of what I'm doing.
Please don't ask questions on why it's done like this. Because I don't know. I just need to know if it's safe or not.
This is safe. Moreover, the standard guarantees that a+1 is b and a+2 is c in the scenario that you describe:
C99 standard, section 6.7.2.2, part 3: If the first enumerator has no =, the value of its enumeration constant is 0. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant.
It's safe. As you seem to recognise yourself, it's really working against the way enums are intended to work, which is as arbitrary labels. However sometimes you want ordering such that a < b < c. If a = 0 and b = 1 and c = 2 in some firm sense, then you don't want an enum, however, you want a variable of type int.

What does the indexing operation do on an integer type in SystemVerilog?

I am trying to port some SystemVerilog code to C++/SystemC, and am a bit stuck on a couple lines where I see strange array indexing. Here is a simplified version of what I see.
typedef enum bit [2:0] {enu_red, enu_blue, enu_green} typ_enum;
typedef struct packed {
bit [3:0] field1;
bit [3:0] field2;
} typ_struct;
...
var int arr_ints[typ_struct];
var int que_ints[$];
typ_struct obj_struct;
typ_enum obj_enum;
int i = 3;
// assume all the declared variables hold valid values at this point
// also assume que_ints[i] is valid
if ((!arr_ints[obj_struct][1]) // these two lines are the problem
&& (que_ints[i][obj_struct])
)
begin
// do something
end
Now after I port this code I get some compiler errors which I completely understand, because the original code doesn't look exactly right to me. In the first line of the if statement, it looks like trying to index an integer type with a boolean value. In the second it looks like trying to index an integer type with an enumerated value. Yet this code apparently works. Can someone please explain what it is doing?
This does bit slicing of the integer type. You will access the actual bits of the underlying int representation.
If que_ints[5] is integer 0xdeadbeef, then:
que_ints[5][3] is 1
que_ints[5][7:4] is 0xe.
In SystemC the range() function is the corollary.
arr_ints is an associative array of type int, where the type used as the key is typ_struct.
So arr_ints[obj_struct] will give you an integer.
Indexing an integer type using [n] will give you the bit at index n.
So arr_ints[obj_struct][1] will give you bit 1 of the integer at arr_ints[obj_struct]
On the second line in question:
que_ints is a queue of type int.
So que_ints[i] will give you the integer at location i in the queue.
In que_ints[i][obj_struct], it will implicitly convert the enum type to an integer value (actually bit[2:0]) and give you the bit index based of that.

Resources