0

I have this code C code that compiles OK on my laptop

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

unsigned int crc32(const void *m, size_t len) {
  const unsigned char *message = m;
  size_t i;
  int j;
  unsigned int byte, crc, mask;

  i = 0;
  crc = 0xFFFFFFFF;
  while (i < len) {
    byte = message[i];
    crc = crc ^ byte;
    for (j = 7; j >= 0; j--) {
      mask = -(crc & 1);
      crc = (crc >> 1) ^ (0xEDB88320 & mask);
    }
    i = i + 1;
  }
  return ~crc;
}

int main() {
  char str[] =
      "620004";
  size_t len = strlen(str);
  unsigned int crc = crc32(str, len);

  size_t len2 = (len + 1) / 2;
  unsigned char arr2[len2];
  for (size_t i = 0; i < len; i += 2) {
    arr2[i / 2] = strtoul((char[3]) {str[i], str[i + 1], '\0'}, 0, 16);
  }
  crc = crc32(arr2, len2);
  printf("CRC: 0x%X\n", crc);

  return 0;
}

And I'm trying to port it to Arduino

#include <CRC32.h>

void setup() {
  Serial.begin(115200);
  uint8_t byteBuffer[] = "620004";
  size_t numBytes = sizeof(byteBuffer) - 1;
  size_t len2 = (numBytes + 1) / 2;
  unsigned char arr2[len2];
  CRC32 crc;
  for (size_t i = 0; i < numBytes; i += 2) {
    arr2[i / 2] = strtoul((char[3]) {byteBuffer[i], byteBuffer[i + 1], '\0'}, 0, 16);
  }
  for (size_t i = 0; i < numBytes; i++){
    crc.update(byteBuffer[i]);
  }

  uint32_t checksum = crc.finalize();
  Serial.print("CRC: ");
  Serial

But I'm getting a

Arduino: 1.8.9 (Linux), Board: "Arduino/Genuino Uno"

/home/nico/Arduino/crc32/crc32.ino: In function 'void setup()':
/home/nico/Arduino/crc32/crc32.ino:11:50: warning: narrowing conversion of 'byteBuffer[i]' from 'uint8_t {aka unsigned char}' to 'char' inside { } [-Wnarrowing]
     arr2[i / 2] = strtoul((char[3]) {byteBuffer[i], byteBuffer[i + 1], '\0'}, 0, 16);
                                                  ^
/home/nico/Arduino/crc32/crc32.ino:11:69: warning: narrowing conversion of 'byteBuffer[(i + 1u)]' from 'uint8_t {aka unsigned char}' to 'char' inside { } [-Wnarrowing]
     arr2[i / 2] = strtoul((char[3]) {byteBuffer[i], byteBuffer[i + 1], '\0'}, 0, 16);
                                                                     ^
crc32:11:84: error: taking address of temporary array
     arr2[i / 2] = strtoul((char[3]) {byteBuffer[i], byteBuffer[i + 1], '\0'}, 0, 16);
                                                                                    ^
exit status 1
taking address of temporary array

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

And I'm not really understanding what's the issue here with the strtoul function and its different behavior on Arduino

3
  • 1
    All those errors are related to (char[3]) {byteBuffer[i], byteBuffer[i + 1], '\0'}, it has nothing to do with strtoul. Who knows how old is the compiler where it works.
    – KIIV
    Jun 6, 2019 at 5:24
  • Btw first two are caused by difference between: char str[] = "620004"; and uint8_t byteBuffer[] = "620004";
    – KIIV
    Jun 6, 2019 at 5:30
  • Please make an answer, don't post an answer as a comment. Comments are for clarifying the question.
    – Nick Gammon
    Jun 6, 2019 at 9:00

2 Answers 2

0

In some architectures a "char" is an "unsigned byte". In others it's a "signed byte". The AVR specification mandates a signed byte for char. Whatever you are compiling on probably mandates an unsigned char.

You cannot assume one or another. If you are working with an array of characters (a "string") you should be assigning it to a char data type. That way the signage of the data type and the "string" content will match.

By using uint8_t you are specifically telling it to use an unsigned byte.

strtoul() expects a char. Since on AVR char is signed, when you try and squeeze an 8-bit value into a 7-bit + sign space it warns you. Which is good. You potentially lose the 8th bit of your data.

The main error, though, is:

error: taking address of temporary array

This is caused by you creating a new temporary array within the parameter list of strtoul.

{byteBuffer[i], byteBuffer[i + 1], '\0'}

Then you take the address of that array and pass it to the function. That is not good. Imagine the situation where the function returns something that is dependent on that address. For instance a function that returns a pointer to all but the first character of the string. Once the function returns that returned pointer points to an area of memory that is no longer valid - the temporary array has already been disposed of.

I know that's not the case in your code, but it's a possibility you can conceive.

Yes, temporary arrays like that are perfectly valid in some versions of C++. But those are fairly recent versions, and the Arduino compiler isn't that recent (I don't know which version introduced them as valid off hand, but we're up to GCC version 8 now. Arduino is still down at version 5.something IIRC).

Suffice it to say, don't use temporary arrays like that (which is a shame, because it's damn useful). Instead you have to assign it to a new array and pass the pointer to that array instead:

char tempArr[3] = {byteBuffer[i], byteBuffer[i + 1], '\0'};
 arr2[i / 2] = strtoul(tempArr, 0, 16);

That way the address you're passing to the function is one that is allocated on the stack and is guaranteed to exist past the lifetime of the function call (right up until the end of the current scope).

0

Not questioning the language issues that were pointed out, but simple answer to what you asked,

"... what's the issue here with ... its different behavior on Arduino"

is that these are two different compilers, possibly written to two different standards of the language (the standards evolve over time) and likely run with different error- and warning suppression switches.

And not to be pedantic but to clarify, it hasn't actually run on the Arduino yet, not having compiled successfully in that environment. The differences you see are entirely due to the differences between the two compilers and the error-options they were run with.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.