문제

Is the defacto method for comparing arrays (in C) to use memcmp from string.h?

I want to compare arrays of ints and doubles in my unit tests

I am unsure whether to use something like:

double a[] = {1.0, 2.0, 3.0};
double b[] = {1.0, 2.0, 3.0};
size_t n = 3;
if (! memcmp(a, b, n * sizeof(double)))
    /* arrays equal */

or to write a bespoke is_array_equal(a, b, n) type function?

도움이 되었습니까?

해결책

memcmp would do an exact comparison, which is seldom a good idea for floats, and would not follow the rule that NaN != NaN. For sorting, that's fine, but for other purposes, you might to do an approximate comparison such as:

bool dbl_array_eq(double const *x, double const *y, size_t n, double eps)
{
    for (size_t i=0; i<n; i++)
        if (fabs(x[i] - y[i]) > eps)
            return false;
    return true;
}

다른 팁

Replace memset with memcmp in your code, and it works.

In your case (as the size both arrays arrays are identical and known during compilation) you can even do:

memcmp(a, b, sizeof(a));

Using memcmp is not generally a good idea. Let's start with the more complex and work down from there.


Though you mentioned int and double, I first want to concentrate on memcmp as a general solution, such as to compare arrays of type:

struct {
    char c;
    // 1
    int i;
    // 2
}

The main problem there is that implementations are free to add padding to structures at locations 1 and 2, making a bytewise comparison potentially false even though the important bits match perfectly.


Now down to doubles. You might think this was better as there's no padding there. However there are other problems.

The first is the treatment of NaN values. IEEE754 goes out of its way to ensure that NaN is not equal to any other value, including itself. For example, the code:

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

int main (void) {
    double d1 = 0.0 / 0.0, d2 = d1;

    if (d1 == d2)
        puts ("Okay");
    else
        puts ("Bad");

    if (memcmp (&d1, &d2, sizeof(double)) == 0)
        puts ("Okay");
    else puts
        ("Bad");

    return 0;
}

will output

Bad
Okay

illustrating the difference.

The second is the treatment of plus and minus zero. These should be considered equal for the purposes of comparison but, as the bit patterns are different, memcmp will say they are different.

Changing the declaration/initialisation of d1 and d2 in the above code to:

 double d1 = 0.0, d2 = -d1;

will make this clear.


So, if structures and doubles are problematic, surely integers are okay. After all, they're always two's complement, yes?

No, actually they're not. ISO mandates one of three encoding schemes for signed integers and the other two (ones' complements and sign/magnitude) suffer from a similar problem as doubles, that fact that both plus and minus zero exist.

So, while they should possibly be considered equal, again the bit patterns are different.

Even for unsigned integers, you have a problem (it's also a problem for signed values as well). ISO states that these representations can have value bits and padding bits, and that the values of the padding bits are unspecified.

So, even for what may seem the simplest case, memcmp can be a bad idea.

The function you're looking for is memcmp, not memset. See the answers to this question for why it might not be a good idea to memcmp an array of doubles though.

memcmp compares two blocks of memory for number of size given

memset is used to initialise buffer with a value for size given

buffers can be compared without using memcmp in following way. same can be changed for different datatypes.

int8_t array_1[] = { 1, 2, 3, 4 }
int8_t array_2[] = { 1, 2, 3, 4 }

uint8_t i;
uint8_t compare_result = 1;

for (i = 0; i < (sizeof(array_1)/sizeof(int8_t); i++)
{
 if (array_1[i] != array_2[i])
  {
   compare_result = 0;
   break;
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top