memcmp()

Hello

I compare two arrays. If first place of myArrayCurrent change from 0 to 1 the code runs perfectly. If the second place change from 0 to 1 there is no difference. See sample 1 and 2 below.

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

// Definition *****************************************************************************
int myArrayCurrent[2];        // Array for all digital inputs
int myArrayLast[2] = {0,0};  // Array to compare with other array

....
void getStatusInput(){
   input52Value = digitalRead(52);        // read status of digital port 52
   input53Value = digitalRead(53);        // read status of digital port 52
   myArrayCurrent[0] = input52Value;       // write status into array
   myArrayCurrent[1] = input53Value;       // write status into array
}

// *** sample 1  // code run ****
// myArrayCurrent[0] = 1
// myArrayCurrent[1] = 0
// myArrayLast[0] = 0
// myArrayLast[0] = 0

// *** sample 2  // code doesn't run ****
// myArrayCurrent[0] = 0
// myArrayCurrent[1] = 1
// myArrayLast[0] = 0
// myArrayLast[0] = 0


if (memcmp (myArrayCurrent, myArrayLast, ARRAY_SIZE(myArrayCurrent)) == 0){ 
        Serial.println("Arrays are equal");
}
else{
        Serial.println("Arrays aren't equal");
}

Where is the different between sample 1 and 2 referenced of memcmp(....)?

Thanks
Mick

That code doesn't compile, please post the full code.

I think the problem is the implied conversion from int* to void*. That conversion loses any information as to the size of each cell in the array. As far as I can tell, memcmp() compares characters. Since the size of your array is 2 elements, the 2 passed to memcmp() equates to 2 characters not 2 ints, so you will only compare the first int in your case.

K&R provide a hint when they say: "The mem... functions are meant for manipulating objects as character arrays; the intent is an interface to efficient routines."

So, in your case here, the size parameter should just be array, not array/array[0] so you know the size in bytes(characters) not the number of elements.

As far as I can tell, memcmp() compares characters.

No, that's not true. memcmp() compares blocks of memory; it could care less what the data type for the block is. There are several errors in the original code:

int myArrayCurrent[2];        // Array for all digital inputs
int myArrayLast[2]; // Array to compare with other array

void setup() {
  
// *** sample 1  // code run ****              You can comment sets in and out of the test
/*
  myArrayCurrent[0] = 1;
  myArrayCurrent[1] = 0;
  myArrayLast[0] = 1;
  myArrayLast[1] = 0;             // ERROR: In your sample, you had element 0 for both indexes

*/
// *** sample 2  // code doesn't run ****
  myArrayCurrent[0] = 0;
  myArrayCurrent[1] = 1;
  myArrayLast[0] = 0;
  myArrayLast[1] = 0;
  
  Serial.begin(115200);
  if (memcmp(myArrayCurrent, myArrayLast, sizeof(myArrayCurrent)) == 0) {   // ERROR: you don't want to look at just 2 bytes
    Serial.println("Arrays are equal");
  }
  else {
    Serial.println("Arrays aren't equal");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
}

In the call to memcmp(), your version only looks at two bytes, which would be a single int value because your macro is properly used to count elements, not bytes of memory. A simple sizeof() operator here is proper because you want to compare the total memory blocks for each array.

Take it up with K&R then, as I quoted. The name for an arbitrary block of memory in C is "an array of characters", after all, the sizeof(char) is defined to be 1.

...after all, the sizeof(char) is defined to be 1.

Really? What about Unicode characters? I still don't think the memcmp() function refers to arrays of chars. It refers to blocks of memory expressed in bytes. (Both the C++ and Linux docs refer to memcmp() as comparing bytes of memory.) Also, since a char is signed quantity, does that mean the memcmp() strips off the high bit and ignores it? I think it is much more descriptive to refer to the blocks as bytes, since those are unsigned entities.

Don't get hung up on the name. 'char' does not imply text. In C, a char is simply the smallest addressable area of storage, which does not have to be a byte. In the original versions of C there was no void pointer and a char pointer was used as a generic pointer.

And yes, sizeof(char) is defined to be 1. I am not sure what Unicode has to do with this since they are wchar_t.

Don't argue with me. Take it up with K&R, Harbison and Steele and The C Programming Faq.

From the GNU C Library:

Function: int memcmp (const void *a1, const void *a2, size_t size)
Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

The function memcmp compares the size bytes of memory beginning at a1 against the size bytes of memory beginning at a2. The value returned has the same sign as the difference between the first differing pair of bytes (interpreted as unsigned char objects, then promoted to int).

If the contents of the two blocks are equal, memcmp returns 0.

It is only the difference between the two memory blocks that is treated as an unsigned char, which is then promoted to an int. I'd agree with your misinterpretation of K&R and the others you cite, but then we'd both be wrong.

That definition would only apply on machines where CHAR_BIT is 8, which, while common, is not a requirement of C, which is why more correct language uses the more generic "array of characters".

Unless, of course you allow for 9-bit bytes.

...which is why more correct language uses the more generic "array of characters".

What is a "more correct language"?

This is an Arduino Forum and the underlying compiler is the GNU compiler, so that is my frame of reference. I learned a long time ago that, when someone tries to bend the fundamental premise of the discussion with a "That-may-be-but-I-don't-believe-it" argument, the best thing to do is let them believe whatever they want. Think what you will, I'll stick with the GNU interpretation upon which the Arduino compiler is built.

How about the arduino libc docs:

The memcmp() function compares the first len bytes of the memory areas s1 and s2. The comparision is performed using unsigned char operations.

Looks like we are both right. 8^)

if (memcmp (myArrayCurrent, myArrayLast, ARRAY_SIZE(myArrayCurrent)) == 0){

You should just compare the whole array, assuming they are both the same size:

if (memcmp (myArrayCurrent, myArrayLast,  sizeof (myArrayCurrent)) == 0){