Electronic – Is using memcmp when updating struct in EEPROM okay

ceeprom

I am writing a generic update function for EEPROM which compares old value with new one and then if values differ writes new one to eeprom. This is the function:

template <typename T>
void update(uint16_t update_address, T& update_value)
{
    // Do not attempt to read until device is ready
    while (!TM_I2C_IsDeviceConnected(EEPROM_I2Cx_, EEPROM_ADDRESS)) {}
    T current_value;
    read(update_address, current_value);
    if (memcmp(&current_value, &update_value, sizeof(T)) != 0)
    {
        // Do not attempt to write until device is ready
        while (!TM_I2C_IsDeviceConnected(EEPROM_I2Cx_, EEPROM_ADDRESS)) {}
        write(update_address, update_value);
    }
}

The problem is comparison. I read that due to padding the variables might differ if they are structures in certain cases and its generally bad idea to use memcmp to compare two structures. But I want my function to be generic. I could assume that "==" operator is defined and use

template <typename T>
void update(uint16_t update_address, T& update_value)
{
    // Do not attempt to read until device is ready
    while (!TM_I2C_IsDeviceConnected(EEPROM_I2Cx_, EEPROM_ADDRESS)) {}
    T current_value;
    read(update_address, current_value);
    if (current_value != update_value)
    {
        // Do not attempt to write until device is ready
        while (!TM_I2C_IsDeviceConnected(EEPROM_I2Cx_, EEPROM_ADDRESS)) {}
        write(update_address, update_value);
    }
}

but I wonder if in this case a "==" operator is REALLY needed. After all I am really just comparing raw bytes, no logic involved (i.e. uint8_t boolean might be true in both structs even if one is 1 and other 100 and this should be handled properly, but in this case it doesn't matter at all as it should be one and same structure byte-wise), but that padding thing has thrown me off a little. My question therefore is Is it okay in this particular case to use memcmp (T can be any type, probably in a lot of cases a structure) and can padding cause any problems or should I assume or rather explicitly demand "==" operator to be defined prior to using the function?

Best Answer

If you really want your template class to be generic (and it seems you want to), you should be using the == operator. Indeed, there might be uninitialized padding bytes in the struct, and your comparison with memcmp would return false even if the fields all have the same value. Of, course, this requires the == operator to be appropriately defined for the underlying type, but that is a safer assumption than considering all bytes of the struct have significance.

This choice has the following consequences:

  • More flexibility: on some underlying types, you may have fields that you don't need/want to compare. It is the case if you have fields that are deduced from other parts of the struct: for example, if the object contains an ID and a name and you know that there is a one-to-one association between name and ID, you just have to compare the ID in the == operator, making the comparison faster. Another example: if, in the struct, there is a hash on the object data, you will first compare the hash to check if objects are unequal to improve speed, before comparing all fields one-by-one.
  • The call of the == operator can eventually be inlined by the compiler, whereas the memcmp call certainly won't (unless it is declared inlineable, but I doubt it). This may allow the complier to produce more efficient code. On the other hand, this may also lead to code bloat. Check the reulting compiled code if you have severe constraints on code size. There are ways to avoid code bloat resulting from templates, but it's outside the scope of your question.