Is there a function to compare two const __FlashStringHelper* strings?

... or I need to write my own ?
I know this question is trivial, but I did not find any reference ...

Should be doable at compile time ( or even when typing the source text ; )

Did you mean the pointer was constant rather than the string itself ?

const __FlashStringHelper* p1;
const __FlashStringHelper* p2;
....

<compare p1,p2 to check if the two pointed progmem strings are equal>

Even in PROGMEM you should avoid duplicate const strings ( Which is a compile time issue ).
I don't know of an avr-gcc feature to check and optimize duplicate strings, however.

At runtime, you might maximally have the task to compare the pointers themselves, if they refer to the same loaction in flash.
Or to compare variable strings in RAM with const strings in PROGMEM.

If the strings are in progmem they are same/different at compile time. Why on earth can't you determine if they are the same?

Either I don't understand what your problem is or you don't understand that you don't have one.

I use string as a way to store data structure in progmem. I need to search in progmem the matching subkey to get the remaining infos.
I could manage the data in many different ways, or I could even copy a const __FlashStringHelper* into a string and then compare with the search string ... but i was curious to know if there is a compare function for a couple of const __FlashStringHelper*.
Quite trivial, is'nt it?

I honestly don't know if there is such a function, but I think by now (10:55am to 8:30pm) I could have developed one.

I did.
But it has nothing to do with the question about a built in function probably faster than mine. If any.
I assume there is not :slight_smile:

This compiles, but I'm not sure if it works:

const __FlashStringHelper* s1;
const __FlashStringHelper* s2;
const __FlashStringHelper* s3;

int strcmp(const __FlashStringHelper* s1, const __FlashStringHelper* s2);

void setup() {
    Serial.begin(115200);
    s1 = F("same");
    s2 = F("different");
    s3 = F("same");

    if (strcmp(s1, s2) == 0)
        Serial.println("s1, s2 same");
    else
        Serial.println("s1, s2 different");

    if (strcmp(s1, s3) == 0)
        Serial.println("s1, s3 same");
    else
        Serial.println("s1, s3 different");

    if (strcmp(s2, s3) == 0)
        Serial.println("s2, s3 same");
    else
        Serial.println("s2, s3 different");
}
void loop() {}

int strcmp(const __FlashStringHelper* s1, const __FlashStringHelper* s2) {
    return strcmp_P(reinterpret_cast<const char*>(s1), reinterpret_cast<const char*>(s2));
}

I am investigating about this.

I'm trying to do something like this:

sprintf(buf,F("

"),digitalRead(RELAY1),digitalRead(RELAY1));

But I receive this error:

cant convert ‘__FlashStringHelper*’ to ‘const char*’ for argument 2 for ‘int sprintf(char*, const char*, ...)’

I've found I can do this:

sprintf_P(buf,PSTR("

"),digitalRead(RELAY1),digitalRead(RELAY1));

But I don't know the difference between F() and PSTR(). Can't find clear documentation about this.

Hey guys, this works for me!

const __FlashStringHelper* s1;
const __FlashStringHelper* s2;
const __FlashStringHelper* s3;

bool strcmp(const __FlashStringHelper* s1, const __FlashStringHelper* s2);

void setup() {
	Serial.begin(115200);

	s1 = F("sameOrNot");
	s2 = F("same");
	s3 = F("same");

	if (strcmp(s1, s2) == true)
		Serial.println("s1, s2 same");
	else
		Serial.println("s1, s2 different");

	if (strcmp(s1, s3) == true)
		Serial.println("s1, s3 same");
	else
		Serial.println("s1, s3 different");

	if (strcmp(s2, s3) == true)
		Serial.println("s2, s3 same");
	else
		Serial.println("s2, s3 different");

}
void loop() {}

bool strcmp(const __FlashStringHelper* s1, const __FlashStringHelper* s2) {
	const char *ptr1 = (const char *)s1;
	const char *ptr2 = (const char *)s2;
	uint16_t i = 0;
	//ex:	s1 = abc, s2 = abcd => s2 contains s1 but not vice-versa ==> difference
	//	s1 = abc, s2 = abc   => s2 contains s1 and vice-versa	    ==> same
	while (!(pgm_read_byte(ptr1 + i) == 0x00 && pgm_read_byte(ptr2 + i) == 0x00)) {
		if (pgm_read_byte(ptr1 + i) != pgm_read_byte(ptr2 + i)) {
			return false;
		}
		i++;
	}
	return true;
}

There is no such function in the <avr/pgmspace.h> include file. As someone has pointed out, why compare two string constants at run time when the answer is known at compile time?

Note: Your function might be confusing because it returns true (1) instead of 0 when the strings are equal. The regular strcmp() returns "an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2."

I needed this function for one of my programs. It's true that both strings are known at compile time, but it can be convenient to do the string matching at runtime. For example, consider a program that creates a bunch of objects with a 'name' field whose type is (const __FlashStringHelper*). Then during the 'setup()', we want to filter those objects using another (const __FlashStringHelper*) string.

In case someone else needs these functions later, and want to save some time, here is the code:

#ifdef ESP8266
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif

// On ESP8266, pgm_read_byte() already takes care of 4-byte alignment, and
// memcpy_P(s, p, 4) makes 4 calls to pgm_read_byte() anyway, so don't bother
// optimizing for 4-byte alignment here.

class __FlashStringHelper;

int compareString(const __FlashStringHelper* a, const __FlashStringHelper* b) {
  const char* aa = reinterpret_cast<const char*>(a);
  const char* bb = reinterpret_cast<const char*>(b);

  while (true) {
    uint8_t ca = pgm_read_byte(aa);
    uint8_t cb = pgm_read_byte(bb);
    if (ca != cb) return (int) ca - (int) cb;
    if (ca == 0) return 0;
    aa++;
    bb++;
  }
}

int compareStringN(const __FlashStringHelper* a, const __FlashStringHelper* b,
    size_t n) {
  const char* aa = reinterpret_cast<const char*>(a);
  const char* bb = reinterpret_cast<const char*>(b);

  while (n > 0) {
    uint8_t ca = pgm_read_byte(aa);
    uint8_t cb = pgm_read_byte(bb);
    if (ca != cb) return (int) ca - (int) cb;
    if (ca == 0) return 0;
    aa++;
    bb++;
    n--;
  }
  return 0;
}

There's actually some subtleties in that code. The inner loop uses 2 boolean expressions, instead of 3. It uses 8-bit operations as much as possible, deferring the 16 (or 32 bit) int operation until the last minute. We also must make sure that the subtraction is done using a signed type, not a uint8_t.

Hope this helps,

Brian

Thank you! Just what I was looking for!

This says memcmp_PF() would work.

Are you sure that memcmp_PF() does that? The docs say, "The memcmp_PF() function compares the first len bytes of the memory areas s1 and flash s2". Also, I thought the "PF" meant "far pointer to progmem", i.e. for ATmega2560 chips.

bxparks:
Are you sure that memcmp_PF() does that?

Nope. Looking at it again I may have misinterpreted the meaning. From the pgmspace.h literature -

The memcmp_PF() function compares the first len bytes of the memory areas s1 and flash s2. The comparision is performed using unsigned char operations. It is an equivalent of memcmp_P() function, except that it is capable working on all FLASH including the exteded area above 64kB.

I mistakenly took 'all' to mean both the source and destination arguments could be in flash. Sorry for any confusion.