1

Code:

unsigned char array_add[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

...

if ((*((uint32_t*)array_add)!=0)||(*((uint32_t*)array_add+1)!=0))
{
 ...
}

I want to check if the array is all zero. So naturally I thought of casting the address of an array, which also happens to be the address of the first member, to an unsigned int 32 type, so I'll only need to do this twice, since it's a 64 bit, 8 byte array. Problem is, it was successfully compiled but the program crashes every time around here.

I'm running my program on an 8bit microcontroller, cortex-M0.

How wrong am I?

PowerPack1
  • 67
  • 4

3 Answers3

2

In theory this could work but in practice there is a thing you aren't considering: aligned memory accesses.

If a uint32_t requires aligned memory access (eg to 4 bytes), then casting an array of unsigned char which has 1 byte alignment requirement to an uint32_t* produces a pointer to an unaligned array of uint32_t.

According to documentation:

There is no support for unaligned accesses on the Cortex-M0 processor. Any attempt to perform an unaligned memory access operation results in a HardFault exception.

In practice this is just dangerous and fragile code which invokes undefined behavior in certain circumstances, as pointed out by Olaf and better explained here.

Community
  • 1
  • 1
Jack
  • 131,802
  • 30
  • 241
  • 343
1

To test multiple bytes as once code could use memcmp().

How speedy this is depends more on the compiler as a optimizing compiler may simple emit code that does a quick 8 byte at once (or 2 4-byte) compare. Even the memcmp() might not be too slow on an 8-bit processor. Profiling code helps.

Take care in micro-optimizations, as they too often are not efficient use of coders` time for significant optimizations.

unsigned char array_add[8] = ...
const unsigned char array_zero[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
if (memcmp(array_zero, array_add, 8) == 0) ... 

Another method uses a union. Be careful not to assume if add.arr8[0] is the most or least significant byte.

union {
  uint8_t array8[8];
  uint64_t array64;
} add; 

// below code will check all 8 of the add.array8[] is they are zero.
if (add.array64 == 0)

In general, focus on writing clear code and reserve such small optimizations to very select cases.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-3

I am not sure but if your array has 8 bytes then just assign base address to a long long variable and compare it to 0. That should solve your problem of checking if the array is all 0.

Edit 1: After Olaf's comment I would say that replace long long with int64_t. However, why do you not a simple loop for iterating the array and checking. 8 chars is all you need to compare.

Edit 2: The other approach could be to OR all elements of array and then compare with 0. If all are 0 then OR will be zero. I do not know whether CMP will be fast or OR. Please refer to Cortex-M0 docs for exact CPU cycles requirement, however, I would expect CMP to be slower.

Shiv
  • 1,912
  • 1
  • 15
  • 21
  • `long long` is not guaranteed to haved 64 bits! Te only thing OP is correct about is using fixed-width types. – too honest for this site Dec 15 '16 at 03:40
  • Page no. 28 of n1570.pdf says that long long has minimum range which requires 64 bits. Please refer me to a place where it says that `long long` is not guaranteed to be 64 bits. Did I miss something else in specification? – Shiv Dec 15 '16 at 03:46
  • 2
    You already cited the relevant part! Read it carefully again! – too honest for this site Dec 15 '16 at 03:47
  • I will try my feeble attempt with the weak mind which I have. – Shiv Dec 15 '16 at 03:48
  • And instead of refering to a page (which depends on the viewer), it would be better to reference the section. – too honest for this site Dec 15 '16 at 03:49
  • Thanks again for pointing that out. But you see that I am a human not a computer but I will try to achieve higher accuracy. – Shiv Dec 15 '16 at 03:52
  • Problem is, neither `long long` (which **is** 64 bits on AAPCS), nor `uint64_t` solve the problem. See my comment to the question. OP uses a completely wrong approach. Your loop-approach would be a clean variant and a good compiler might unroll it, if possible. But on an embedded CPU like the CM0, I'd target for speed if that does not obfuscate the code and there are alternatives, depending on what OP wants actually to achieve. – too honest for this site Dec 15 '16 at 03:56
  • @Olaf: I guess using an `union { uint8_t data[8]; uint32_t data32[2]; };` could be a solution, if I recall correctly C11 allows type punning so that bytes are reinterpreted but I'm not sure about previous standards. – Jack Dec 15 '16 at 04:24
  • @Jack why not `union {uint8_t data[8]; uint64_t[1];}` – Shiv Dec 15 '16 at 04:26
  • @Jack: That is correct. Actually a `union` is the _only_ compliant way for type-punning! And modern compilers like gcc or clang heavily rely on the code not violating the effective type rule. – too honest for this site Dec 15 '16 at 12:06
  • @Shiv: Just that: a 1-element array does not make much sense. But I agree this would be a solution and what I had in mind. Just was too lazy to provide an answer on my own (and there are already hundreds of q&a about this). – too honest for this site Dec 15 '16 at 12:09