C function crashed at array parameter - c

I write a function like:
void func1(char chx[], int y)
{
int wsn = 0;
wsn = *(int *) (&chx[2]);
if (wsn == 0) {
...
}
}
Compiler works well, no warning, no error. But when the code is running, seems it get a wild pointer. the code crashed.
But code like the following works well:
wsn = (chx[5]<< 24) + (chx[4] << 16) + (chx[3] << 8) + chx[2];
Wonder why it was crashed

As I observed in a comment to the question, some machines don't like it if you pass a misaligned address and try to treat it as an int *. For example, many RISC machines require the address of a 4-byte quantity to be aligned on a 4-byte boundary, but an arbitrary char *is not necessarily sufficiently aligned. If you get a SIGBUS error instead of a SIGSEGV, this is often strongly indicative of the trouble.
Since the Renesas site prominently mentions 'RISC' and Wikipedia affirms this, I am moderately confident that your problem is that the address passed to func1() is not sufficiently well aligned for &chx[2] to be valid as a 4-byte (presumably) int *.
Your code doing the byte operations works because it only requires the data to be byte aligned, and all data on a byte-addressed machine is byte aligned.
You could consider using:
void func1(char chx[], int y)
{
int wsn = 0;
int *ip = (int *)&chx[2];
if ((uintptr_t)ip & 0x3 == 0)
wsn = *ip;
else
wsn = (chx[5]<< 24) + (chx[4] << 16) + (chx[3] << 8) + chx[2];
if (wsn == 0)
{
…
}
}
But you may do just as well with the shift expression anyway. One thing to watch, though; those + operators should perhaps be | operators, especially if plain char is a signed type. If it works as it stands, then plain char is probably an unsigned type. Both are allowed by standard C, but which is used has to be documented.

Related

C - Write struct to NVM byte by byte

I have a struct of different data types, which should be written into the non-volatile memory. It is possible to write it word after word, but I'm unsure, how I can read a word from my struct.
The struct looks like this:
typedef struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
} __attribute__(( aligned(4))) test_struct_t;
How is it possible, to write word by word from this struct? With the aligned(4) attribute this should be possible, right?
How is it possible, to write word by word from this struct? With the aligned(4) attribute this should be possible, right?
Hmm, no, the answer to that is that writing the struct to a non-volatile storage system using 32bit "words" would make the resulting data unportable across systems due to possible Byte Endianness concerns.
EDIT: If the data isn't going anywhere
If the stored data isn't leaving the system, Endianness isn't an issue and that part of my original answer (further on) can be safely ignored.
I would still consider manually marking the padding in the struct and updating the naming as detailed below (see: Ease of use / Portability).
Also, if the NVM has a memory address and the standard library is available (or a compiler builtin function) - memcpy will be a simple solution and there's no need to worry about alignments and other implementation details.
Can we use a uint32_t *?
The issue is that if we use a pointer that violates the standard (invokes undefined behavior), than the compiler is free to assume that the data in the struct was never (properly) accessed and optimize away our read/write operations.
For example, this might leave us with old data in the struct even though we thought we performed a "read" operation (that was optimized away).
There is a good solution offered in #Lundin's answer.
Lundin's solution is one way to deal with the restrictions stated in section 6.5 (paragraph 7) of the C11 standard - restrictions that C compilers rely upon when optimizing your code:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
...
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.
A similar issue occurs in section 6.2.7 (paragraph 2) of the standard:
declarations that refer to the same object or function shall have compatible type; otherwise, the behavior is undefined.
#Lundin's approach uses a union type, which is the second to last solution. My approach used the last approach (a char type) when storing the data.
Another approach would use void * to move the calculation to an independent function (same approved as memcpy). This will prevent the compiler from assuming anything as void * conversions are always allowed.
Original Answer:
I think the problem of writing to non-volatile storage is divided into 2 main issues:
Byte Endianness - different systems have different memory models and we want the non-volatile storage to be as system agnostic as possible.
Ease of use / Portability - we don't want to rewrite a lot of pieces of code every time we update the structure and we want to minimize compiler specific instructions.
Byte Endiannes
If we store the data on one system and than load it in another system, the byte ordering may be different between systems, breaking our data scheme.
To solve Byte Endiannes it's important to read and store 32bit numbers and 16 bit numbers in a way that is byte order agnostic. This means storing the specific bits in a pre-determined bytes.
I wrote a few macros for that (based on the facil.io open source framework):
/** write uint16_t to a buffer independently of system's of endieness. */
#define u2buf16(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint16_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint16_t)(i)) >> 8) & 0xFF; \
} while (0)
/** write uint32_t to a buffer independently of system's of endieness. */
#define u2buf32(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint32_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint32_t)(i)) >> 8) & 0xFF; \
((uint8_t *)(dest))[2] = (((uint32_t)(i)) >> 16) & 0xFF; \
((uint8_t *)(dest))[3] = (((uint32_t)(i)) >> 24) & 0xFF; \
} while (0)
/** read uint16_t from a buffer independently of system's of endieness. */
#define buf2u16(src) \
((uint16_t)(((uint8_t *)(src))[0]) | ((uint16_t)(((char *)(src))[1]) << 8))
/** read uint32_t from a buffer independently of system's of endieness. */
#define buf2u32(src) \
(((uint32_t)(((uint8_t *)(src))[0])) | \
(((uint32_t)(((uint8_t *)(src))[1])) << 8) | \
(((uint32_t)(((uint8_t *)(src))[2])) << 16) | \
(((uint32_t)(((uint8_t *)(src))[3])) << 24))
Ease of use / Portability
The best way to deal with this is to encapsulate the code in proper functions.
Before I did that, I updated the example in a number of small ways:
I removed the __attribute__(( aligned(4))) instruction, as it's both compiler specific and unnecessary.
I renamed the struct's postfix from _t to _s.
The _t type postfix is reserved by the POSIX standard and mustn't be used in user-code.
The _s postfix is a common way to indicate struct (or _u for unions, and _p for pointers, etc'). This is a personal preference and depends on where you work.
I added a uint8_t reserved; field where padding would have naturally occurred, both making room for future updates and making sure no unknown padding was present in the struct (here I use this quality only during testing).
This came out as:
typedef struct {
uint8_t value1;
uint8_t reserved; /* reserved for future versions */
int16_t value2;
uint32_t value3;
float value4;
} test_struct_s;
For the function decelerations (API) I used the root of the type name (test_struct) as the name spaced appended the function names at the end.
This approach too is a common way to manage namespaces and is a personal preference that depends on the guidelines in your workspace.
They came up as:
static void test_struct_write(char *dest, test_struct_s *src);
static void test_struct_read(test_struct_s *dest, char *src);
Now, the first thing to do is to write tests for the code.
By writing a bit in every byte before a read/write roundtrip, it is possible to effectively test the read/write roundtrip for correctness.
In addition, we want to make sure that each field in the tested struct had a different bit set, so we make sure to test that we're not mixing up values.
/** test read/write behavior. */
static void test_struct_rw_test(void) {
/*
* write defferent values to each struct field, making sure all bytes have a
* set bit at least once during the test.
*
* perform a read/write roundtri[ and test that the set bit has the same
* value.
*/
for (size_t i = 0; i < 32; ++i) {
union {
float f;
uint32_t i;
} u;
/* a float with a single bit set somewhere */
u.i = ((uint32_t)1U << ((i + 1) & 31));
/* a different bit is set in every struct field */
test_struct_s r, s = {
.value1 = (1U << ((i + 0) & 31)),
.reserved = (1U << ((i + 1) & 31)),
.value2 = (1U << ((i + 2) & 31)),
.value3 = (1U << ((i + 3) & 31)),
.value4 = u.f,
};
char buf[sizeof(s)];
test_struct_write(buf, &s);
test_struct_read(&r, buf);
/* we can use memcmp only because we control the padded bytes with
* `reserved` */
if (memcmp(&s, &r, sizeof(s))) {
fprintf(stderr, "FATAL: Read/Write rountrip test failed (at %zu)\n", i);
fprintf(stderr, "%u!=%u\n%u!=%u\n%d!=%d\n%u!=%u\n%f!=%f\n", s.value1,
r.value1, s.reserved, r.reserved, s.value2, r.value2, s.value3,
r.value3, s.value4, r.value4);
exit(-1);
}
}
}
Next we need to actually code the read / write functions themselves.
As you will notice, I am assigning each 8 bit sequence to a specific byte, allowing the code to be endianness and system agnostic.
The buffer being written to or read from MUST be (at least) 96 bits long (12 bytes), or the functions will overflow.
/** "safely" write test_struct_s to a buffer. buffer MUST be 96 bits long. */
static void test_struct_write(char *dest, test_struct_s *src) {
union {
float f;
uint32_t i;
} u;
if (sizeof(float) != sizeof(uint32_t))
goto system_error; /* will be tested by the compiler and optimized away... */
u.f = src->value4;
dest[0] = src->value1;
dest[1] = src->reserved;
u2buf16(dest + 2, src->value2);
u2buf32(dest + 4, src->value3);
u2buf32(dest + 8, u.i);
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** "safely" read test_struct_s from a buffer. buffer MUST be 96 bytes long. */
static void test_struct_read(test_struct_s *dest, char *src) {
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
union {
float f;
uint32_t i;
} u;
dest->value1 = src[0];
dest->reserved = src[1];
dest->value2 = buf2u16(src + 2);
dest->value3 = buf2u32(src + 4);
u.i = buf2u32(src + 8);
dest->value4 = u.f;
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
And we're done.
The whole of the code looks something like this:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* added a `reserved` field to mark natural struct padding AND control padded
* bytes.
*
* now, sizeof(test_struct_s) == 96
*/
typedef struct {
uint8_t value1;
uint8_t reserved; /* reserved for future versions */
int16_t value2;
uint32_t value3;
float value4;
} test_struct_s;
static void test_struct_write(char *dest, test_struct_s *src);
static void test_struct_read(test_struct_s *dest, char *src);
/** write uint16_t to a buffer independently of system's of endieness. */
#define u2buf16(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint16_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint16_t)(i)) >> 8) & 0xFF; \
} while (0)
/** write uint32_t to a buffer independently of system's of endieness. */
#define u2buf32(dest, i) \
do { \
((uint8_t *)(dest))[0] = ((uint32_t)(i)) & 0xFF; \
((uint8_t *)(dest))[1] = (((uint32_t)(i)) >> 8) & 0xFF; \
((uint8_t *)(dest))[2] = (((uint32_t)(i)) >> 16) & 0xFF; \
((uint8_t *)(dest))[3] = (((uint32_t)(i)) >> 24) & 0xFF; \
} while (0)
/** read uint16_t from a buffer independently of system's of endieness. */
#define buf2u16(src) \
((uint16_t)(((uint8_t *)(src))[0]) | ((uint16_t)(((char *)(src))[1]) << 8))
/** read uint32_t from a buffer independently of system's of endieness. */
#define buf2u32(src) \
(((uint32_t)(((uint8_t *)(src))[0])) | \
(((uint32_t)(((uint8_t *)(src))[1])) << 8) | \
(((uint32_t)(((uint8_t *)(src))[2])) << 16) | \
(((uint32_t)(((uint8_t *)(src))[3])) << 24))
/** "safely" write test_struct_s to a buffer. buffer MUST be 96 bytes long. */
static void test_struct_write(char *dest, test_struct_s *src) {
union {
float f;
uint32_t i;
} u;
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
u.f = src->value4;
dest[0] = src->value1;
dest[1] = src->reserved;
u2buf16(dest + 2, src->value2);
u2buf32(dest + 4, src->value3);
u2buf32(dest + 8, u.i);
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** "safely" read test_struct_s from a buffer. buffer MUST be 96 bytes long. */
static void test_struct_read(test_struct_s *dest, char *src) {
if (sizeof(float) != sizeof(uint32_t))
goto system_error;
union {
float f;
uint32_t i;
} u;
dest->value1 = src[0];
dest->reserved = src[1];
dest->value2 = buf2u16(src + 2);
dest->value3 = buf2u32(src + 4);
u.i = buf2u32(src + 8);
dest->value4 = u.f;
return;
system_error:
fprintf(stderr,
"FATAL: Program requires a modern system where floats are 32 bits "
"(sizeof(float) == %zu)\n",
sizeof(float));
exit(-1);
}
/** test read/write behavior. */
static void test_struct_rw_test(void) {
/*
* write defferent values to each struct field, making sure all bytes have a
* set bit at least once during the test.
*
* perform a read/write roundtri[ and test that the set bit has the same
* value.
*/
for (size_t i = 0; i < 32; ++i) {
union {
float f;
uint32_t i;
} u;
/* a float with a single bit set somewhere */
u.i = ((uint32_t)1U << ((i + 1) & 31));
test_struct_s r, s = {
.value1 = (1U << ((i + 0) & 31)),
.reserved = (1U << ((i + 1) & 31)),
.value2 = (1U << ((i + 2) & 31)),
.value3 = (1U << ((i + 3) & 31)),
.value4 = u.f,
};
char buf[sizeof(s)];
test_struct_write(buf, &s);
test_struct_read(&r, buf);
/* we can use memcmp only because we control the padded bytes with
* `reserved` */
if (memcmp(&s, &r, sizeof(s))) {
fprintf(stderr, "FATAL: Read/Write rountrip test failed (at %zu)\n", i);
fprintf(stderr, "%u!=%u\n%u!=%u\n%d!=%d\n%u!=%u\n%f!=%f\n", s.value1,
r.value1, s.reserved, r.reserved, s.value2, r.value2, s.value3,
r.value3, s.value4, r.value4);
exit(-1);
}
}
}
int main(void) {
test_struct_rw_test();
fprintf(stderr, "PASSED\n");
return 0;
}
The following solution seems to work fine:
test_struct_t test_t;
uint16_t size = sizeof(test_struct_t)/sizeof(uint32_t);
uint32_t *ptr = (uint32_t *)&test_t;
for(uint16_t i = 0; i < size; i++)
{
writeWordNVM(i, *ptr);
ptr++;
}
Apart from alignment, the issue here is the C type system, where each position in memory that contains a declared variable or has been de-referenced by the program through a value access, has an internal "type tag" formally known as effective type. This is used for optimization purposes, so that the compiler can know if pointer types of different kinds may alias. That is, if they could refer to the same memory location. Informally this whole set of rules is called the "strict aliasing rules". What is the strict aliasing rule?
Simple example of pointer aliasing: if you have void func (float* f){ *f = 1.0f; } and a global int foo;, the compiler is free to assume that the function writing to *f won't modify the contents of foo when doing so.
Traditionally, embedded system compilers never used optimization based on aliasing assumptions, but with gcc entering the embedded world, this is no longer necessarily the case. If you compile with gcc -fno-strict-aliasing, you can dodge the problem, but the code won't be portable.
This is kind of a language defect. To portably avoid the strict aliasing rules, you must use cumbersome tricks such as union type punning. That is, create a union containing the struct and an array of uint32_t both, then do all de-referencing on the array member. Example:
#include <stdio.h>
#include <stdint.h>
typedef struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
} test_struct_t;
_Static_assert(_Alignof(test_struct_t) == _Alignof(uint32_t),
"Inconsistent alignment in test_struct_t");
typedef union
{
struct
{
uint8_t value1;
int16_t value2;
uint32_t value3;
float value4;
};
uint32_t u32 [sizeof(test_struct_t)/sizeof(uint32_t)];
} test_union_t;
int main(int argc, char **argv)
{
test_union_t test = {.value1 = 1, .value2 = 2};
printf("%.8X\n", test.u32[0]);
return 0;
}
Here I first made a typedef of the struct just to check with static assert if the alignment is ok, removing the non-standard __attribute__(( aligned(4))).
Then when creating the type punning union, I made the same struct anonymous just so that we don't have to type out test.test_struct.value1 rather than test.value1, kind of hiding the fact that it's a union.
I then initialized some members of the union by name and de-referenced them through a type punned uint32_t. This prints 00020001 on my little endian machine, apparently there's a padding byte after value1, which is as expected.

Correct way of calling a c function that expects const char8 string[] as parameter

Inside an ISR of a microcontroller I am attempting to call a function as follows:
//adc.c
static volatile char uartBuf[6]={0};
CY_ISR(ISR_ADC)
{
for (uint8_t i=0; i < NS; i++)
total += adc2_buffer0[i];
uartBuf[0] = total >> 24 & 0xFF;
uartBuf[1] = total >> 16 & 0xFF;
uartBuf[2] = total >> 8 & 0xFF;
uartBuf[3] = total & 0xFF;
uartBuf[4] = '\n';
UART_1_PutString(uartBuf); //doesn't work
}
//uart.c
void UART_1_PutString(const char8 string[])
{
...
}
However in the function UART_1_PutString, string always points to '\0' rather than uartBuf?
What could be the problem? Theoretically the variable uartBuf shouldn't be optimized out by the compiler.
The code seems correct
Do you mean that string[0] == '\0'?
Maybe (total >> 24 & 0xFF) == 0 always (or most of the times).
EDIT:
The function should be
void UART_1_PutString(const volatile unsigned char buff[]);
It shouldn't be called string, because it's not text, it's just a buffer (it looks like it at least).
unsigned because the "string", comes from some unsigned bit manipulation after some maths, which could cause an invalid signed value (unlikely to fail, but the rule should be: char for text, unsigned char for unknown data (everything else)).
volatile because if not, you are discarding the volatile qualifier. A compiler with high enough flags (in GCC: -Wall -Wextra -Werror will highlight almost everything as errors) will warn you about that. The compiler could think that the contents of the function can be simplified even before knowing that you will call it with volatile data, and therefore will optimize something which shouldn't be optimized.
You could also add the restrict keyword (C11) if no other function will access that buffer at the same time, so that you help the compiler produce better code:
void UART_1_PutString(const volatile unsigned char buff[restrict]);
EDIT2:
You should state the size of the buffer if it is only going to be called with that buffer, or also pass the size of the buffer to the function if not:
void UART_1_PutString(const volatile unsigned char buff[restrict 6]);
(6 should probably be replaced by some macro) or
void UART_1_PutString(size_t size, const volatile unsigned char buff[restrict size]);

Why this way to detect machine storage methods is incorrect? (Using C language)

I missed a problem when I doing my homework.
Computer memory in the storage of data where there are big-endian storage and small-endian storage two methods, in order to detect a machine storage method, a student wrote the following procedure:
union NUM {
int a;
char b;
} num;
int main(){
num.b = 0xff;
if (num.a! = 0xff)
printf ("bigend");
else
printf ("smallend");
return 0;
}
But he found the program running on the x86 machine, print out is actually 'bigend', which is clearly wrong. Do you know where the problem is?
How should this program be modified?
I have asked my teacher, the topic is correct. I have found some information in some websites, but it makes me more confused. Why this question is not incorrect? And where the problem actually is?
Assuming an int (and therefore the union as a whole) is 4 bytes, writing to num.b only writes to one of those 4 bytes, leaving the rest uninitialized. Subsequently reading num.a reads those uninitialized bytes, invoking undefined behavior.
The bytes in the union must be set to all 0s so that the content is well defined.
#include <stdio.h>
#include <string.h>
union NUM {
int a;
char b;
} num;
int main(){
// set all bytes of num to 0 first
memset(&num, 0, sizeof(num));
num.b = 0xff;
if (num.a! = 0xff)
printf ("bigend");
else
printf ("smallend");
return 0;
}
Type-punning is undefined behavior in C. When you read num.a you are violating the strict aliasing rules, so the compiler is allowed to generate code that may give back anything. Which it does.
To avoid this, you need to use memcpy():
int a = 0x00010203;
char bytes[sizeof(a)];
memcpy(bytes, &a, sizeof(a));
if(bytes[0] == 03) {
printf("small endian\n");
} else ...

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/

C job interview - casting and comparing

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

Resources