Hello,
how can I compare if the values of a struct are != to the values of another struct?
Detailed description of what I want to do:
I use a "struct" to save the settings values of my program in EEPROM.
struct settings_type {
int one=10;
int two=20;
float three=30.0;
}
settings_type=s{};
I save in the EEPROM both the current settings values (starting at address 0), and the default values (starting at address 100).
When I want to reset the settings to default, I simply copy the values from address 100 to address 0.
void reset_settings_to_defaults(){
EEPROM.get(100, s);
EEPROM.put(0, s);
}
At the first start of the program, the eeprom need to be initialized.
I can't simply check "eeprom blank", because it works only the first time the board is flashed.
I need to check if the eeprom starting at 100 is initializes exactly with the values I specified in the struct type definition (see above... 10, 20, 30.0).
//at first boot
settings_type s_default;
EEPROM.get(100, s_default);
if(s_default!=s) { // <-- problem in this line
EEPROM.put(0, s);
EEPROM.put(100, s);
}
void load_settings(void){
EEPROM.get(0, s);
}
void save_settings(){
EEPROM.put(0, s);
}
Just "loop"over them.
if(s.one != t.one || s.two != t.two || s.three != t.three)
Btw, one two three are pretty useless names 
Just overload the == and != operators.
struct settings_type {
int one=10;
int two=20;
float three=30.0;
bool operator==(settings_type const & rhs) const {
return this->one == rhs.one
&& this->two == rhs.two
&& this->three == rhs.three;
}
bool operator!=(settings_type const & rhs) const {
return !(*this == rhs);
}
}
Then you can use
settings_type s1;
settings_type s2;
s1.one = 42;
if (s1 != s2)
// True
Pieter
But watch out for the Safe Bool Idiom. You are not no longer really work with a struct but a class.
@PieterP
Why do you qualify the local members by this-> ?
That would normaly only be needed if there are local variables/parameters hiding the name.
You are checking the third member (which is a float) for equality, which is not a good idea generally, wouldn't
abs(three - rhs.three) < 0.0001
(or something like it with a more sensible value) be safer?
@septillion
What differences besides the standard visibility of objects do you see in C++ between struct and class?
@Whandall, nothing. But the OP used a struct as a name space/storage. Now switching to making it a proper object (with methods) does open a new can of worms to be aware of. It's no longer only storage for some variables.
septillion:
But watch out for the Safe Bool Idiom. You are not no longer really work with a struct but a class.
Could you elaborate? I'm not sure I understand what you're getting at.
The simplest way to compare two structs for an exact match would be a memcmp.
@sterretje, yeah, I think I would like that idea the most as well.
Whandall:
What differences besides the standard visibility of objects do you see in C++ between struct and class?
One thing that comes to mind is I don't think you can 'malloc(sizeof(settings_type))' when the struct / class contains a method. You have to 'new' it.
sterretje:
The simplest way to compare two structs for an exact match would be a memcmp.
That probably won't have the desired effect if one of the struct's members is a pointer since you'd be interested in the value being pointed to, not its address.
gfvalvo:
One thing that comes to mind is I don't think you can 'malloc(sizeof(settings_type))' when the struct / class contains a method. You have to 'new' it.
I think you can.
struct Settings {
int one;
int two;
float three;
Settings () : one(10), two(20), three(30.0) {}
bool operator==(Settings const & other) const {
return one == other.one &&
two == other.two &&
abs(three - other.three) < 0.0001;
}
bool operator!=(Settings const & other) const {
return !(*this == other);
}
};
const Settings defaultSet;
Settings dynamicSet;
void setup() {
Serial.begin(250000);
void* checker = malloc(sizeof(Settings));
Settings* randomSet = reinterpret_cast<Settings*>(checker);
if (*randomSet == defaultSet) {
Serial.println(F("randomSet happens to be same as default"));
} else {
Serial.println(F("randomSet is different from default"));
}
free(checker);
if (dynamicSet == defaultSet) {
Serial.println(F("both start up the same"));
}
dynamicSet.one += 1;
if (dynamicSet != defaultSet) {
Serial.println(F("dynamicSet was changed"));
}
}
void loop() {}
randomSet is different from default
both start up the same
dynamicSet was changed
Added: Using class with public: gives exactly the same result and behaviour.
Why would you want to leave out any initialization in the first place?
I forgot to mention that in the real program I will have about 50 items inside the struct, with meaningful names. Formats are bool, byte, int and float.
I can't compare them one by one (s.one==default.one || s.two==default.two ....), because it would be non practical (especially when I add/remove parameters, I want to make this change in one place only, which is where I declare the struct datatype).
A bitwise comparison of the whole struct would be perfect.
Why I don't find memcmp() in the arduino reference?
if (memcmp(s_temp, s, sizeof(s)!=0)) {
}
From the error message seems that the format of the arguments should be: int memcmp(const void*, const void*, size_t)
Passing the pointer compiles fine. I'll see if this works
if (memcmp(&s_temp, &s, sizeof(s)!=0)) {
}
ingdemurtas:
Passing the pointer compiles fine. I'll see if this works
if (memcmp(&s_temp, &s, sizeof(s)!=0)) {
}
That won't work. Why the "!= 0"? It converts the result to a boolean (0 or 1), which is not the size you're looking for!
Check your parentheses.
ingdemurtas:
Why I don't find memcmp() in the arduino reference?
Because it is not an Arduino function but part of the standard C library,
which is documented (for AVR) on the AVR Libc Home Page.
And I bet Google would point to a couple of other maybe better descriptions.
This seems like a non-problem to me. Why not simply reset the settings like this and forget about initializing the default settings in EEPROM at all:
void reset_settings_to_defaults(){
static const settings_type s_default;
s = s_default;
EEPROM.put(0, s);
}
Then you don't have to worry about comparing the settings structures.
gfvalvo:
That probably won't have the desired effect if one of the struct's members is a pointer since you'd be interested in the value being pointed to, not its address.
But you would also not store pointers in eeprom 
ingdemurtas:
I forgot to mention that in the real program I will have about 50 items inside the struct, with meaningful names. Formats are bool, byte, int and float.
Just letting you know, equality comparison between floats is generally discouraged. Floats are commonly thought of as containing "real" numbers in comparison to the number types that only contain integers, but floats have their own rounding issues as well. There are also many numbers that you can write that a float cannot represent perfectly. 0.1 for example, has to be rounded. If you perform calculations on the floats, depending on how the rounding happens two values you think should be equivalent might not be.
You are right.
I corrected it. It works now 
thanks everyone for the help!
settings_type s_temp;
EEPROM.get(defaultSettings_EPROM_Address, s_temp);
Serial.println("eeprom check");
delay(2000);
if( memcmp(&s_temp, &s, sizeof(s)) == 0) { //
//eeprom default area is initialized to default
Serial.println("eeprom match");
}
else{
Serial.println("eeprom NOT match! Initializing");
delay(5000);
EEPROM.put(Settings_EPROM_Address, s);
EEPROM.put(defaultSettings_EPROM_Address, s);
}