C job interview - casting and comparing - c

I was confronted with a tricky (IMO) question. I needed to compare two MAC addresses, in the most efficient manner.
The only thought that crossed my mind in that moment was the trivial solution - a for loop, and comparing locations, and so I did, but the interviewer was aiming to casting.
The MAC definition:
typedef struct macA {
char data[6];
} MAC;
And the function is (the one I was asked to implement):
int isEqual(MAC* addr1, MAC* addr2)
{
int i;
for(i = 0; i<6; i++)
{
if(addr1->data[i] != addr2->data[i])
return 0;
}
return 1;
}
But as mentioned, he was aiming for casting.
Meaning, to somehow cast the MAC address given to an int, compare both of the addresses, and return.
But when casting, int int_addr1 = (int)addr1;, only four bytes will be casted, right? Should I check the remaining ones? Meaning locations 4 and 5?
Both char and int are integer types so casting is legal, but what happens
in the described situation?

If he is really dissatisfied with this approach (which is essentially a brain fart, since you aren't comparing megabytes or gigabytes of data, so one shan't really be worrying about "efficiency" and "speed" in this case), just tell him that you trust the quality and speed of the standard library:
int isEqual(MAC* addr1, MAC* addr2)
{
return memcmp(&addr1->data, &addr2->data, sizeof(addr1->data)) == 0;
}

If your interviewer demands that you produce undefined behavior, I would probably look for a job elsewhere.
The correct initial approach would be to store the MAC address in something like a uint64_t, at least in-memory. Then comparisons would be trivial, and implementable efficiently.

Cowboy time:
typedef struct macA {
char data[6];
} MAC;
typedef struct sometimes_works {
long some;
short more;
} cast_it
typedef union cowboy
{
MAC real;
cast_it hack;
} cowboy_cast;
int isEqual(MAC* addr1, MAC* addr2)
{
assert(sizeof(MAC) == sizeof(cowboy_cast)); // Can't be bigger
assert(sizeof(MAC) == sizeof(cast_it)); // Can't be smaller
if ( ( ((cowboy_cast *)addr1)->hack.some == ((cowboy_cast *)addr2)->hack.some )
&& ( ((cowboy_cast *)addr1)->hack.more == ((cowboy_cast *)addr2)->hack.more ) )
return (0 == 0);
return (0 == 42);
}

There is nothing wrong with an efficient implementation, for all you know this has been determined to be hot code that is called many many times. And in any case, its okay for interview questions to have odd constraints.
Logical AND is a priori a branching instruction due to short-circuit evaluation even if it doesn't compile this way, so lets avoid it, we don't need it. Nor do we need to convert our return value to a true bool (true or false, not 0 or anything that's not zero).
Here is a fast solution on 32-bit:
XOR will capture the differences, OR will record difference in both parts, and NOT will negate the condition into EQUALS, not UNEQUAL. The LHS and RHS are independent computations, so a superscalar processor can do this in parallel.
int isEqual(MAC* addr1, MAC* addr2)
{
return ~((*(int*)addr2 ^ *(int*)addr1) | (int)(((short*)addr2)[2] ^ ((short*)addr1)[2]));
}
EDIT
The purpose of the above code was to show that this could be done efficiently without branching. Comments have pointed out this C++ classifies this as undefined behavior. While true, VS handles this fine. Without changing the interviewer's struct definition and function signature, in order to avoid undefined behavior an extra copy must be made. So the non-undefined behavior way without branching but with an extra copy would be as follows:
int isEqual(MAC* addr1, MAC* addr2)
{
struct IntShort
{
int i;
short s;
};
union MACU
{
MAC addr;
IntShort is;
};
MACU u1;
MACU u2;
u1.addr = *addr1; // extra copy
u2.addr = *addr2; // extra copy
return ~((u1.is.i ^ u2.is.i) | (int)(u1.is.s ^ u2.is.s)); // still no branching
}

This would work on most systems,and be faster than your solution.
int isEqual(MAC* addr1, MAC* addr2)
{
return ((int32*)addr1)[0] == ((int32*)addr2)[0] && ((int16*)addr1)[2] == ((int16*)addr2)[2];
}
would inline nicely too, could be handy at the center of loop on a system where you can check the details are viable.

Non-portable casting solution.
In a platform I use (PIC24 based), there is a type int48, so making a safe assumption char is 8 bits and the usual alignment requirements:
int isEqual(MAC* addr1, MAC* addr2) {
return *((int48_t*) &addr1->data) == *((int48_t*) &addr2->data);
}
Of course, this is not usable on many platforms, but then so are a number of solutions that are not portable either, depending on assumed int size, no padding, etc.
The highest portable solution (and reasonably fast given a good compiler) is the memcmp() offered by #H2CO3.
Going to a higher design level and using a wide enough integer type like uint64_t instead of struct macA, as suggested by Kerrek SB, is very appealing.

To do type punning correctly you have to use an union. Otherwise you will break the rules strict aliasing which certain compilers follow, and the result will be undefined.
int EqualMac( MAC* a , MAC* b )
{
union
{
MAC m ;
uint16_t w[3] ;
} ua , ub ;
ua.m = *a ;
ub.m = *b ;
if( ua.w[0] != ub.w[0] )
return 0 ;
if( ua.w[1] != ub.w[1] )
return 0 ;
if( ua.w[2] != ub.w[2] )
return 0 ;
return 1 ;
}
According to C99 it is safe to read from an union member that is not the last used to store a value in it.
If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

You have a MAC structure (which contains an array of 6 bytes),
typedef struct {
char data[6];
} MAC;
Which agrees with this article about typedef for fixed length byte array.
The naive approach would be to assume the MAC address is word aligned (which is probably what the interviewer wanted), albeit not guaranteed.
typedef unsigned long u32;
typedef signed long s32;
typedef unsigned short u16;
typedef signed short s16;
int
MACcmp(MAC* mac1, MAC* mac2)
{
if(!mac1 || !mac2) return(-1); //check for NULL args
u32 m1 = *(u32*)mac1->data;
U32 m2 = *(u32*)mac2->data;
if( m1 != m2 ) return (s32)m1 - (s32)m2;
u16 m3 = *(u16*)(mac1->data+4);
u16 m2 = *(u16*)(mac2->data+4);
return (s16)m3 - (s16)m4;
}
Slightly safer would be to interpret the char[6] as a short[3] (MAC more likely to be aligned on even byte boundaries than odd),
typedef unsigned short u16;
typedef signed short s16;
int
MACcmp(MAC* mac1, MAC* mac2)
{
if(!mac1 || !mac2) return(-1); //check for NULL args
u16* p1 = (u16*)mac1->data;
u16* p2 = (u16*)mac2->data;
for( n=0; n<3; ++n ) {
if( *p1 != *p2 ) return (s16)*p1 - (s16)*p2;
}
return(0);
}
Assume nothing, and copy to word aligned storage, but the only reason for typecasting here is to satisfy the interviewer,
typedef unsigned short u16;
typedef signed short s16;
int
MACcmp(MAC* mac1, MAC* mac2)
{
if(!mac1 || !mac2) return(-1); //check for NULL args
u16 m1[3]; u16 p2[3];
memcpy(m1,mac1->data,6);
memcpy(m2,mac2->data,6);
for( n=0; n<3; ++n ) {
if( m1[n] != m2[n] ) return (s16)m1[n] - (s16)m2[n];
}
return(0);
}
Save yourself lots of work,
int
MACcmp(MAC* mac1, MAC* mac2)
{
if(!mac1 || !mac2) return(-1);
return memcmp(mac1->data,mac2->data,6);
}

Function memcmp will eventually do the loop itself. So by using it, you would basically just make things less efficient (due to the additional function-call).
Here is an optional solution:
typedef struct
{
int x;
short y;
}
MacAddr;
int isEqual(MAC* addr1, MAC* addr2)
{
return *(MacAddr*)addr1 == *(MacAddr*)addr2;
}
The compiler will most likely convert this code into two comparisons, since the MacAddr structure contains two fields.
Cavity: unless your CPU supports unaligned load/store operations, addr1 and addr2 must be aligned to 4 bytes (i.e., they must be located in addresses that are divisible by 4). Otherwise, a memory access violation will most likely occur when the function is executed.
You may divide the structure into 3 fields of 2 bytes each, or 6 fields of 1 byte each (reducing the alignment restriction to 2 or 1 respectively). But bare in mind that a single comparison in your source code is not necessarily a single comparison in the executable image (i.e., during runtime).
BTW, unaligned load/store operations by themselves may add runtime latency, if they require more "nops" in the CPU pipeline. This is really a matter of CPU architecture, which I doubt they meant to "dig into" that far in your job interview. However, in order to assert that the compiled code does not contain such operations (if indeed they are "expensive"), you could ensure that the variables are always aligned to 8 bytes AND add a #pragma (compiler directive) telling the compiler "not to worry about this".

May be he had in mind a definition of MAC that used unsigned char and was thinking to:
int isEqual(MAC* addr1, MAC* addr2) { return strncmp((*addr1).data,(*addr2).data,6)==0; }
which implies a cast from (unsigned char *) to (char *).
Anyway bad question.

By the way, for those truly looking for a performant answer, the following is branchless, and while it does more fetches (one per char), they should all be from the same cache line, so not very expensive.
int isEqual(MAC* addr1, MAC* addr2)
{
return
(addr1->data[0] == addr2->data[0])
& (addr1->data[1] == addr2->data[1])
& (addr1->data[2] == addr2->data[2])
& (addr1->data[3] == addr2->data[3])
& (addr1->data[4] == addr2->data[4])
& (addr1->data[5] == addr2->data[5])
;
}
See it live (and branchless) here

Related

switch have error "expected a type specifier" (C) [duplicate]

I want to store mixed data types in an array. How could one do that?
You can make the array elements a discriminated union, aka tagged union.
struct {
enum { is_int, is_float, is_char } type;
union {
int ival;
float fval;
char cval;
} val;
} my_array[10];
The type member is used to hold the choice of which member of the union is should be used for each array element. So if you want to store an int in the first element, you would do:
my_array[0].type = is_int;
my_array[0].val.ival = 3;
When you want to access an element of the array, you must first check the type, then use the corresponding member of the union. A switch statement is useful:
switch (my_array[n].type) {
case is_int:
// Do stuff for integer, using my_array[n].ival
break;
case is_float:
// Do stuff for float, using my_array[n].fval
break;
case is_char:
// Do stuff for char, using my_array[n].cvar
break;
default:
// Report an error, this shouldn't happen
}
It's left up to the programmer to ensure that the type member always corresponds to the last value stored in the union.
Use a union:
union {
int ival;
float fval;
void *pval;
} array[10];
You will have to keep track of the type of each element, though.
Array elements need to have the same size, that is why it's not possible. You could work around it by creating a variant type:
#include <stdio.h>
#define SIZE 3
typedef enum __VarType {
V_INT,
V_CHAR,
V_FLOAT,
} VarType;
typedef struct __Var {
VarType type;
union {
int i;
char c;
float f;
};
} Var;
void var_init_int(Var *v, int i) {
v->type = V_INT;
v->i = i;
}
void var_init_char(Var *v, char c) {
v->type = V_CHAR;
v->c = c;
}
void var_init_float(Var *v, float f) {
v->type = V_FLOAT;
v->f = f;
}
int main(int argc, char **argv) {
Var v[SIZE];
int i;
var_init_int(&v[0], 10);
var_init_char(&v[1], 'C');
var_init_float(&v[2], 3.14);
for( i = 0 ; i < SIZE ; i++ ) {
switch( v[i].type ) {
case V_INT : printf("INT %d\n", v[i].i); break;
case V_CHAR : printf("CHAR %c\n", v[i].c); break;
case V_FLOAT: printf("FLOAT %f\n", v[i].f); break;
}
}
return 0;
}
The size of the element of the union is the size of the largest element, 4.
There's a different style of defining the tag-union (by whatever name) that IMO make it much nicer to use, by removing the internal union. This is the style used in the X Window System for things like Events.
The example in Barmar's answer gives the name val to the internal union. The example in Sp.'s answer uses an anonymous union to avoid having to specify the .val. every time you access the variant record. Unfortunately "anonymous" internal structs and unions is not available in C89 or C99. It's a compiler extension, and therefore inherently non-portable.
A better way IMO is to invert the whole definition. Make each data type its own struct, and put the tag (type specifier) into each struct.
typedef struct {
int tag;
int val;
} integer;
typedef struct {
int tag;
float val;
} real;
Then you wrap these in a top-level union.
typedef union {
int tag;
integer int_;
real real_;
} record;
enum types { INVALID, INT, REAL };
Now it may appear that we're repeating ourselves, and we are. But consider that this definition is likely to be isolated to a single file. But we've eliminated the noise of specifiying the intermediate .val. before you get to the data.
record i;
i.tag = INT;
i.int_.val = 12;
record r;
r.tag = REAL;
r.real_.val = 57.0;
Instead, it goes at the end, where it's less obnoxious. :D
Another thing this allows is a form of inheritance. Edit: this part is not standard C, but uses a GNU extension.
if (r.tag == INT) {
integer x = r;
x.val = 36;
} else if (r.tag == REAL) {
real x = r;
x.val = 25.0;
}
integer g = { INT, 100 };
record rg = g;
Up-casting and down-casting.
Edit: One gotcha to be aware of is if you're constructing one of these with C99 designated initializers. All member initializers should be through the same union member.
record problem = { .tag = INT, .int_.val = 3 };
problem.tag; // may not be initialized
The .tag initializer can be ignored by an optimizing compiler, because the .int_ initializer that follows aliases the same data area. Even though we know the layout (!), and it should be ok. No, it ain't. Use the "internal" tag instead (it overlays the outer tag, just like we want, but doesn't confuse the compiler).
record not_a_problem = { .int_.tag = INT, .int_.val = 3 };
not_a_problem.tag; // == INT
You can do a void * array, with a separated array of size_t. But you lose the information type.
If you need to keep information type in some way keep a third array of int (where the int is an enumerated value) Then code the function that casts depending on the enum value.
Union is the standard way to go. But you have other solutions as well. One of those is tagged pointer, which involves storing more information in the "free" bits of a pointer.
Depending on architectures you can use the low or high bits, but the safest and most portable way is using the unused low bits by taking the advantage of aligned memory. For example in 32-bit and 64-bit systems, pointers to int must be multiples of 4 (assuming int is a 32-bit type) and the 2 least significant bits must be 0, hence you can use them to store the type of your values. Of course you need to clear the tag bits before dereferencing the pointer. For example if your data type is limited to 4 different types then you can use it like below
void* tp; // tagged pointer
enum { is_int, is_double, is_char_p, is_char } type;
// ...
uintptr_t addr = (uintptr_t)tp & ~0x03; // clear the 2 low bits in the pointer
switch ((uintptr_t)tp & 0x03) // check the tag (2 low bits) for the type
{
case is_int: // data is int
printf("%d\n", *((int*)addr));
break;
case is_double: // data is double
printf("%f\n", *((double*)addr));
break;
case is_char_p: // data is char*
printf("%s\n", (char*)addr);
break;
case is_char: // data is char
printf("%c\n", *((char*)addr));
break;
}
If you can make sure that the data is 8-byte aligned (like for pointers in 64-bit systems, or long long and uint64_t...), you'll have one more bit for the tag.
This has one disadvantage that you'll need more memory if the data have not been stored in a variable elsewhere. Therefore in case the type and range of your data is limited, you can store the values directly in the pointer. This technique has been used in the 32-bit version of Chrome's V8 engine, where it checks the least significant bit of the address to see if that's a pointer to another object (like double, big integers, string or some object) or a 31-bit signed value (called smi - small integer). If it's an int, Chrome simply does an arithmetic right shift 1 bit to get the value, otherwise the pointer is dereferenced.
On most current 64-bit systems the virtual address space is still much narrower than 64 bits, hence the high most significant bits can also be used as tags. Depending on the architecture you have different ways to use those as tags. ARM, 68k and many others can be configured to ignore the top bits, allowing you to use them freely without worrying about segfault or anything. From the linked Wikipedia article above:
A significant example of the use of tagged pointers is the Objective-C runtime on iOS 7 on ARM64, notably used on the iPhone 5S. In iOS 7, virtual addresses are 33 bits (byte-aligned), so word-aligned addresses only use 30 bits (3 least significant bits are 0), leaving 34 bits for tags. Objective-C class pointers are word-aligned, and the tag fields are used for many purposes, such as storing a reference count and whether the object has a destructor.
Early versions of MacOS used tagged addresses called Handles to store references to data objects. The high bits of the address indicated whether the data object was locked, purgeable, and/or originated from a resource file, respectively. This caused compatibility problems when MacOS addressing advanced from 24 bits to 32 bits in System 7.
https://en.wikipedia.org/wiki/Tagged_pointer#Examples
On x86_64 you can still use the high bits as tags with care. Of course you don't need to use all those 16 bits and can leave out some bits for future proof
In prior versions of Mozilla Firefox they also use small integer optimizations like V8, with the 3 low bits used to store the type (int, string, object... etc.). But since JägerMonkey they took another path (Mozilla’s New JavaScript Value Representation, backup link). The value is now always stored in a 64-bit double precision variable. When the double is a normalized one, it can be used directly in calculations. However if the high 16 bits of it are all 1s, which denote an NaN, the low 32-bits will store the address (in a 32-bit computer) to the value or the value directly, the remaining 16-bits will be used to store the type. This technique is called NaN-boxing or nun-boxing. It's also used in 64-bit WebKit's JavaScriptCore and Mozilla's SpiderMonkey with the pointer being stored in the low 48 bits. If your main data type is floating-point, this is the best solution and delivers very good performance.
Read more about the above techniques: https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations

speed difference between using structs and variables as input arguments of a function

To optimize functions which have same pattern, I am considering two ways of implementation.
A environment of this function may used is inside of interrupts on embedded software. This is why I am faced of difficulty since considering of speed capacity is required.
In my opinion, following case 1 and 2 have same speed feature. However my colleague said there might be difference since first case need to access using pointer but second does not.
Which one is more faster?
I need your help to implement efficient code with speed.
typedef struct
{
unsigned char member1;
unsigned char member2;
..
unsigned char member10;
} my_struct
my_struct input[10];
void My_ISR1( void )
{
...
sub_func1( input[1] );
return 0;
}
void My_ISR2( void )
{
...
sub_func1( input[2] );
return 0;
}
void sub_func1( my_struct my_struct_input )
{
if( my_struct_input.member1 < my_struct_input.member2 )
{
...
}
...
return 0;
}
CASE2)
unsigned char member1of1;
unsigned char member2of1;
...
unsigned char member10of10;
void My_ISR1( void )
{
...
sub_func1( member1of1, ..., member10of1 );
return 0;
}
void My_ISR2( void )
{
...
sub_func1( member1of2, ..., member10of2 );
return 0;
}
void sub_func1( unsigned char member1,
unsigned char member2, ...,
unsigned char member 10 )
{
if( member1 < member2 )
{
...
}
...
return 0;
}
The only way to be sure if one implementation is faster than another, for your compiler, and your problem space, in your code, on your hardware, for your particular use case, is to measure it.
However, of the two options presented, I would expect the pass-by-struct to be slightly faster (by the way, in your code you are not passing by pointer)
In both presented cases, a copy of the variables is passed to the function.
In both cases, this results in a copy of 10 bytes, however given the struct is contiguous, this may be slightly faster.
However, a better option might be to pass by pointer eg:
void sub_func1( my_struct* my_struct_input )
{
if(my_struct_input->member1 < my_struct_input<member2)
///........
}
This way, instead of copying 10 individual variables, or a struct of 10 bytes, we are only copying one (presumably 32-bit, but it depends) address.
It does have the downside that you are now operating on the exact same struct as the caller, but that can be resolved using const pointers.
One further thing to consider, is that while the function call might be faster in one scenario or another, you have to look at the bigger picture. While passing a struct-pointer should be faster, you have to also consider the overhead in constructing the struct - if you have to assign the struct members from existing variables, this obviously adds extra processing, which must be factored into the consideration.

C Function to Convert float to byte array

I'm trying to make a function that will accept a float variable and convert it into a byte array. I found a snippet of code that works, but would like to reuse it in a function if possible.
I'm also working with the Arduino environment, but I understand that it accepts most C language.
Currently works:
float_variable = 1.11;
byte bytes_array[4];
*((float *)bytes_array) = float_variable;
What can I change here to make this function work?
float float_test = 1.11;
byte bytes[4];
// Calling the function
float2Bytes(&bytes,float_test);
// Function
void float2Bytes(byte* bytes_temp[4],float float_variable){
*(float*)bytes_temp = float_variable;
}
I'm not so familiar with pointers and such, but I read that (float) is using casting or something?
Any help would be greatly appreciated!
Cheers
*EDIT: SOLVED
Here's my final function that works in Arduino for anyone who finds this. There are more efficient solutions in the answers below, however I think this is okay to understand.
Function: converts input float variable to byte array
void float2Bytes(float val,byte* bytes_array){
// Create union of shared memory space
union {
float float_variable;
byte temp_array[4];
} u;
// Overite bytes of union with float variable
u.float_variable = val;
// Assign bytes to input array
memcpy(bytes_array, u.temp_array, 4);
}
Calling the function
float float_example = 1.11;
byte bytes[4];
float2Bytes(float_example,&bytes[0]);
Thanks for everyone's help, I've learnt so much about pointers and referencing in the past 20 minutes, Cheers Stack Overflow!
Easiest is to make a union:
#include <stdio.h>
int main(void) {
int ii;
union {
float a;
unsigned char bytes[4];
} thing;
thing.a = 1.234;
for (ii=0; ii<4; ii++)
printf ("byte %d is %02x\n", ii, thing.bytes[ii]);
return 0;
}
Output:
byte 0 is b6
byte 1 is f3
byte 2 is 9d
byte 3 is 3f
Note - there is no guarantee about the byte order… it depends on your machine architecture.
To get your function to work, do this:
void float2Bytes(byte bytes_temp[4],float float_variable){
union {
float a;
unsigned char bytes[4];
} thing;
thing.a = float_variable;
memcpy(bytes_temp, thing.bytes, 4);
}
Or to really hack it:
void float2Bytes(byte bytes_temp[4],float float_variable){
memcpy(bytes_temp, (unsigned char*) (&float_variable), 4);
}
Note - in either case I make sure to copy the data to the location given as the input parameter. This is crucial, as local variables will not exist after you return (although you could declare them static, but let's not teach you bad habits. What if the function gets called again…)
Here's a way to do what you want that won't break if you're on a system with a different endianness from the one you're on now:
byte* floatToByteArray(float f) {
byte* ret = malloc(4 * sizeof(byte));
unsigned int asInt = *((int*)&f);
int i;
for (i = 0; i < 4; i++) {
ret[i] = (asInt >> 8 * i) & 0xFF;
}
return ret;
}
You can see it in action here: http://ideone.com/umY1bB
The issue with the above answers is that they rely on the underlying representation of floats: C makes no guarantee that the most significant byte will be "first" in memory. The standard allows the underlying system to implement floats however it feels like -- so if you test your code on a system with a particular kind of endianness (byte order for numeric types in memory), it will stop working depending on the kind of processor you're running it on.
That's a really nasty, hard-to-fix bug and you should avoid it if at all possible.
I would recommend trying a "union".
Look at this post:
http://forum.arduino.cc/index.php?topic=158911.0
typedef union I2C_Packet_t{
sensorData_t sensor;
byte I2CPacket[sizeof(sensorData_t)];
};
In your case, something like:
union {
float float_variable;
char bytes_array[4];
} my_union;
my_union.float_variable = 1.11;
Yet another way, without unions:
(Assuming byte = unsigned char)
void floatToByte(byte* bytes, float f){
int length = sizeof(float);
for(int i = 0; i < length; i++){
bytes[i] = ((byte*)&f)[i];
}
}
this seems to work also
#include <stddef.h>
#include <stdint.h>
#include <string.h>
float fval = 1.11;
size_t siz;
siz = sizeof(float);
uint8_t ures[siz];
memcpy (&ures, &fval, siz);
then
float utof;
memcpy (&utof, &ures, siz);
also for double
double dval = 1.11;
siz = sizeof(double);
uint8_t ures[siz];
memcpy (&ures, &dval, siz);
then
double utod;
memcpy (&utod, &ures, siz);
Although the other answers show how to accomplish this using a union, you can use this to implement the function you want like this:
byte[] float2Bytes(float val)
{
my_union *u = malloc(sizeof(my_union));
u->float_variable = val;
return u->bytes_array;
}
or
void float2Bytes(byte* bytes_array, float val)
{
my_union u;
u.float_variable = val;
memcpy(bytes_array, u.bytes_array, 4);
}
**conversion without memory reference** \
#define FLOAT_U32(x) ((const union {float f; uint32_t u;}) {.f = (x)}.u) // float->u32
#define U32_FLOAT(x) ((const union {float f; uint32_t u;}) {.u = (x)}.f) // u32->float
**usage example:**
float_t sensorVal = U32_FLOAT(eeprom_read_dword(&sensor));
First of all, some embedded systems 101:
Anyone telling you to use malloc/new on Arduino have no clue what they are talking about. I wrote a fairly detailed explanation regarding why here: Why should I not use dynamic memory allocation in embedded systems?
You should avoid float on 8 bit microcontrollers since it leads to incredibly inefficient code. They do not have a FPU, so the compiler will be forced to load a very resource-heavy software floating point library to make your code work. General advise here.
Regarding pointer conversions:
C allows all manner of wild and crazy pointer casts. However, there are lots of situations where it can lead to undefined behavior if you cast a character byte array's address into a float* and then de-reference it.
If the address of the byte array is not aligned, it will lead to undefined behavior on systems that require aligned access. (AVR doesn't care about alignment though.)
If the byte array does not contain a valid binary representation of a float number, it could become a trap representation. Similarly you must keep endianess in mind. AVR is an 8-bitter but it's regarded as little endian since it uses little endian format for 16 bit addresses.
It leads to undefined behavior because it goes against the C language "effective type" system, also known as a "strict pointer aliasing violation". What is the strict aliasing rule?
Going the other way around is fine though - taking the address of a float variable and converting it to a character pointer, then de-reference that character pointer to access individual bytes. Multiple special rules in C allows this for serialization purposes and hardware-related programming.
Viable solutions:
memcpy always works fine and then you won't have to care about alignment and strict aliasing. You still have to care about creating a valid floating point representation though.
union "type punning" as demonstrated in other answers. Note that such type punning will assume a certain endianess.
Bit shifting individual bytes and concatenating with | or masking with & as needed. The advantage of this is that it's endianess-independent in some scenarios.
float f=3.14;
char *c=(char *)&f;
float g=0;
char *d=(char *)&g;
for(int i=0;i<4;i++) d[i]=c[i];
/* Now g=3.14 */
Cast your float as char, and assign the address to the char pointer.
Now, c[0] through c[3] contain your float.
http://justinparrtech.com/JustinParr-Tech/c-access-other-data-types-as-byte-array/

How can mixed data types (int, float, char, etc) be stored in an array?

I want to store mixed data types in an array. How could one do that?
You can make the array elements a discriminated union, aka tagged union.
struct {
enum { is_int, is_float, is_char } type;
union {
int ival;
float fval;
char cval;
} val;
} my_array[10];
The type member is used to hold the choice of which member of the union is should be used for each array element. So if you want to store an int in the first element, you would do:
my_array[0].type = is_int;
my_array[0].val.ival = 3;
When you want to access an element of the array, you must first check the type, then use the corresponding member of the union. A switch statement is useful:
switch (my_array[n].type) {
case is_int:
// Do stuff for integer, using my_array[n].ival
break;
case is_float:
// Do stuff for float, using my_array[n].fval
break;
case is_char:
// Do stuff for char, using my_array[n].cvar
break;
default:
// Report an error, this shouldn't happen
}
It's left up to the programmer to ensure that the type member always corresponds to the last value stored in the union.
Use a union:
union {
int ival;
float fval;
void *pval;
} array[10];
You will have to keep track of the type of each element, though.
Array elements need to have the same size, that is why it's not possible. You could work around it by creating a variant type:
#include <stdio.h>
#define SIZE 3
typedef enum __VarType {
V_INT,
V_CHAR,
V_FLOAT,
} VarType;
typedef struct __Var {
VarType type;
union {
int i;
char c;
float f;
};
} Var;
void var_init_int(Var *v, int i) {
v->type = V_INT;
v->i = i;
}
void var_init_char(Var *v, char c) {
v->type = V_CHAR;
v->c = c;
}
void var_init_float(Var *v, float f) {
v->type = V_FLOAT;
v->f = f;
}
int main(int argc, char **argv) {
Var v[SIZE];
int i;
var_init_int(&v[0], 10);
var_init_char(&v[1], 'C');
var_init_float(&v[2], 3.14);
for( i = 0 ; i < SIZE ; i++ ) {
switch( v[i].type ) {
case V_INT : printf("INT %d\n", v[i].i); break;
case V_CHAR : printf("CHAR %c\n", v[i].c); break;
case V_FLOAT: printf("FLOAT %f\n", v[i].f); break;
}
}
return 0;
}
The size of the element of the union is the size of the largest element, 4.
There's a different style of defining the tag-union (by whatever name) that IMO make it much nicer to use, by removing the internal union. This is the style used in the X Window System for things like Events.
The example in Barmar's answer gives the name val to the internal union. The example in Sp.'s answer uses an anonymous union to avoid having to specify the .val. every time you access the variant record. Unfortunately "anonymous" internal structs and unions is not available in C89 or C99. It's a compiler extension, and therefore inherently non-portable.
A better way IMO is to invert the whole definition. Make each data type its own struct, and put the tag (type specifier) into each struct.
typedef struct {
int tag;
int val;
} integer;
typedef struct {
int tag;
float val;
} real;
Then you wrap these in a top-level union.
typedef union {
int tag;
integer int_;
real real_;
} record;
enum types { INVALID, INT, REAL };
Now it may appear that we're repeating ourselves, and we are. But consider that this definition is likely to be isolated to a single file. But we've eliminated the noise of specifiying the intermediate .val. before you get to the data.
record i;
i.tag = INT;
i.int_.val = 12;
record r;
r.tag = REAL;
r.real_.val = 57.0;
Instead, it goes at the end, where it's less obnoxious. :D
Another thing this allows is a form of inheritance. Edit: this part is not standard C, but uses a GNU extension.
if (r.tag == INT) {
integer x = r;
x.val = 36;
} else if (r.tag == REAL) {
real x = r;
x.val = 25.0;
}
integer g = { INT, 100 };
record rg = g;
Up-casting and down-casting.
Edit: One gotcha to be aware of is if you're constructing one of these with C99 designated initializers. All member initializers should be through the same union member.
record problem = { .tag = INT, .int_.val = 3 };
problem.tag; // may not be initialized
The .tag initializer can be ignored by an optimizing compiler, because the .int_ initializer that follows aliases the same data area. Even though we know the layout (!), and it should be ok. No, it ain't. Use the "internal" tag instead (it overlays the outer tag, just like we want, but doesn't confuse the compiler).
record not_a_problem = { .int_.tag = INT, .int_.val = 3 };
not_a_problem.tag; // == INT
You can do a void * array, with a separated array of size_t. But you lose the information type.
If you need to keep information type in some way keep a third array of int (where the int is an enumerated value) Then code the function that casts depending on the enum value.
Union is the standard way to go. But you have other solutions as well. One of those is tagged pointer, which involves storing more information in the "free" bits of a pointer.
Depending on architectures you can use the low or high bits, but the safest and most portable way is using the unused low bits by taking the advantage of aligned memory. For example in 32-bit and 64-bit systems, pointers to int must be multiples of 4 (assuming int is a 32-bit type) and the 2 least significant bits must be 0, hence you can use them to store the type of your values. Of course you need to clear the tag bits before dereferencing the pointer. For example if your data type is limited to 4 different types then you can use it like below
void* tp; // tagged pointer
enum { is_int, is_double, is_char_p, is_char } type;
// ...
uintptr_t addr = (uintptr_t)tp & ~0x03; // clear the 2 low bits in the pointer
switch ((uintptr_t)tp & 0x03) // check the tag (2 low bits) for the type
{
case is_int: // data is int
printf("%d\n", *((int*)addr));
break;
case is_double: // data is double
printf("%f\n", *((double*)addr));
break;
case is_char_p: // data is char*
printf("%s\n", (char*)addr);
break;
case is_char: // data is char
printf("%c\n", *((char*)addr));
break;
}
If you can make sure that the data is 8-byte aligned (like for pointers in 64-bit systems, or long long and uint64_t...), you'll have one more bit for the tag.
This has one disadvantage that you'll need more memory if the data have not been stored in a variable elsewhere. Therefore in case the type and range of your data is limited, you can store the values directly in the pointer. This technique has been used in the 32-bit version of Chrome's V8 engine, where it checks the least significant bit of the address to see if that's a pointer to another object (like double, big integers, string or some object) or a 31-bit signed value (called smi - small integer). If it's an int, Chrome simply does an arithmetic right shift 1 bit to get the value, otherwise the pointer is dereferenced.
On most current 64-bit systems the virtual address space is still much narrower than 64 bits, hence the high most significant bits can also be used as tags. Depending on the architecture you have different ways to use those as tags. ARM, 68k and many others can be configured to ignore the top bits, allowing you to use them freely without worrying about segfault or anything. From the linked Wikipedia article above:
A significant example of the use of tagged pointers is the Objective-C runtime on iOS 7 on ARM64, notably used on the iPhone 5S. In iOS 7, virtual addresses are 33 bits (byte-aligned), so word-aligned addresses only use 30 bits (3 least significant bits are 0), leaving 34 bits for tags. Objective-C class pointers are word-aligned, and the tag fields are used for many purposes, such as storing a reference count and whether the object has a destructor.
Early versions of MacOS used tagged addresses called Handles to store references to data objects. The high bits of the address indicated whether the data object was locked, purgeable, and/or originated from a resource file, respectively. This caused compatibility problems when MacOS addressing advanced from 24 bits to 32 bits in System 7.
https://en.wikipedia.org/wiki/Tagged_pointer#Examples
On x86_64 you can still use the high bits as tags with care. Of course you don't need to use all those 16 bits and can leave out some bits for future proof
In prior versions of Mozilla Firefox they also use small integer optimizations like V8, with the 3 low bits used to store the type (int, string, object... etc.). But since JägerMonkey they took another path (Mozilla’s New JavaScript Value Representation, backup link). The value is now always stored in a 64-bit double precision variable. When the double is a normalized one, it can be used directly in calculations. However if the high 16 bits of it are all 1s, which denote an NaN, the low 32-bits will store the address (in a 32-bit computer) to the value or the value directly, the remaining 16-bits will be used to store the type. This technique is called NaN-boxing or nun-boxing. It's also used in 64-bit WebKit's JavaScriptCore and Mozilla's SpiderMonkey with the pointer being stored in the low 48 bits. If your main data type is floating-point, this is the best solution and delivers very good performance.
Read more about the above techniques: https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations

comparing values of two data structures

I have two data structures:
typedef struct{
int a;
int b;
int c;
}EVENTS;
EVENTS typeone[20];
EVENTS typetwo[20];
These have been filled. typeone has been filled till typeone[5] and typetwo till typetwo[8].
I just want to compare the first six of typeone and typetwo and see if there are equal in all their members.
Is there a way to do typeone[1] == typetwo[1]
Basically comparing all the values inside the datastructure at [1].
Is there a short way to do this or would I have to loop through each member and compare separately?
Thanks
This is a comp.lang.c FAQ. In a nutshell, no, C does not support struct comparison with the == operator (the answer in the FAQ states a few reasons as to why this is hard in the general case). You have to write your own function and compare member by member. As was pointed out, memcmp() is not a guaranteed way due to unspecified behavior when accessing padding bytes.
int eventsequal (const EVENTS *const a, const EVENTS *const b)
{
if (a->a != b->a) return 0;
if (a->b != b->b) return 0;
if (a->c != b->c) return 0;
return 1;
}
And then your example typeone[1] == typetwo[1] becomes
if (eventsequal (typeone + 1, typetwo + 1)) {
/* They're equal. */
}
To avoid the problem of padding, you have to compare the fields individually. This doesn't have to be all that horrible:
#include <stdbool.h>
bool EVENTS_equal(const EVENTS *e1, const EVENTS *e2)
{
return e1->a == e2->a && e1->b == e2->b && e1->c == e2->c;
}
then just loop:
size_t i;
bool equal = true;
for(i = 0; i < 6; ++i)
{
if(!EVENTS_equal(typeone + i, typetwo + i))
{
equal = 0;
break;
}
}
it's not that much code really, and of course you could trivially encapsulate the looping in a function that cross-compares the n first slots of two EVENTS arrays.
typedef struct{
int a;
int b;
int c;
}EVENTS;
#pragma pack(1)
EVENTS typeone[20];
EVENTS typetwo[20];
#pragma pack()
int equal(EVENTS* v1, EVENTS* v2)
{
return 0==memcmp(v1, v2, sizeof(*v1));
}
Note #pragma pack(1). It ensures that there are no padding bytes in the structures. This way memcmp will not try to compare padding bytes and the comparison is way faster than a field-by-field method, but while in this case the performance is unlikely to be adversely affected, take:
typedef struct{
char a;
long b;
} somestruct;
#pragma pack(1)
somestruct foo;
#pragma pack()
Retrieving foo.b will take much more machine code than in case of padded structures, because it will miss word-aligned position where it can be retrieved with a single 32-bit instruction, it will have to be picked out with four byte-reads, and then assembled into the target register from these four pieces. So, take the performance impact into account.
Also, check if your compiler supports #pragma pack. Most modern compilers do, but exceptions may still happen.

Resources