Rules of c language are very confusing

xox

Joined Sep 8, 2017
795
I forgot that C does not support the equality operator for two identically structured structs. So to compare two structs with many fields for equality we must write different code either a member by member compare or a block compare of memory.

Ah yes, the beloved C boilerplate. Provided there are no "complex" pointers involved you can always use a simple macro.


Code:
#define MEQ(a, b) (memcmp(&a, &b, sizeof(a)) == 0)

Or even


Code:
#define MEQ(a, b) ((sizeof(a) == sizeof(b))\
? (memcmp(&a, &b, sizeof(a)) == 0) : 0)
Granted, without type-checking we are back to old arguments about how C can be so unsafe if used improperly!

That's what C++ is for.

Exactly. Although I must say I never did bother to learn the newer version of the language. I still use the older syntax.


https://codebeautify.org/c-formatter-beautifier


C:
#include <stdio.h>



int main(void) {


  int i = 1, d = 1;


  for (;;) {


    printf("%d", i);


    i += d;


    if (!i) break;


    if (i == 2446) d = -1;


  }


  puts(": PRIME");


}

Kind of long for a signature, if you ask me. Plus the minified version isn't nearly as likely to be confused for a response. I also just like the idea of this short snippet of code producing such a large prime number. Although admittedly Python is capable of producing even more impressive feats in that respect:


Code:
import sys
sys.stdout.write(str(2*(2618163402417*2**1290000-1)+1))
print(": SAFE PRIME")

Big-integers are baked into the language.
 

ApacheKid

Joined Jan 12, 2015
1,118
Yes, these are of course all viable options, so long as one maintains discipline and strives for consistency that's the best we can hope for.

But there are potential gremlins, the memcmp option would probably perform a byte by byte compare of the memory block since it wants to establish equality or greater/lesser, that's a large cost when all we want to know is "are these the same" rather than "how do these differ".

The following however would exploit the "short circuiting" inherent in the evaluation of logical expressions and exploit the fact that multi-byte integer compares are efficiently implemented as single instructions on most if not all, processors.

Code:
    // This is the MCU's unique ID, these addresses are specific to the F4 family.

    unsigned long ID0 = (*(unsigned long *)0x1FFF7A10);
    unsigned long ID1 = (*(unsigned long *)0x1FFF7A14);
    unsigned long ID2 = (*(unsigned long *)0x1FFF7A18);

    if (ID0 == board1.fields[0] && ID1 == board1.fields[1] && ID2 == board1.fields[2])
    {
        known = 1;
        return known;
    }
So as soon as any equality check evaluates as false the remainder of the expression is not evaluated, I suspect then that this would require less CPU cycles. If we're really concerned about overall performance of code that might be many thousands of statements, then the effect of relying on memcmp and so on might be quite detrimental especially when we factor in the cost of call/return which involves stack frame management, another cost.

One could craft a compare macro that was sophisticated enough to examine the size of the block and if a multiple of 4 or 8, then iterate over the memory blocks using an int or long pointer and compare that way, that could end up being pretty quick, I've done stuff like this before myself (on minicomputers and Windows) but its reinventing the wheel and a developer's time should ideally focus on the problem domain rather than making up for language deficiencies - IMHO !
 
Last edited:

xox

Joined Sep 8, 2017
795
Yes, these are of course all viable options, so long as one maintains discipline and strives for consistency that's the best we can hope for.

But there are potential gremlins, the memcmp option would probably perform a byte by byte compare of the memory block since it wants to establish equality or greater/lesser, that's a large cost when all we want to know is "are these the same" rather than "how do these differ".

The following however would exploit the "short circuiting" inherent in the evaluation of logical expressions and exploit the fact that multi-byte integer compares are efficiently implemented as single instructions on most if not all, processors.

Code:
    // This is the MCU's unique ID, these addresses are specific to the F4 family.

    unsigned long ID0 = (*(unsigned long *)0x1FFF7A10);
    unsigned long ID1 = (*(unsigned long *)0x1FFF7A14);
    unsigned long ID2 = (*(unsigned long *)0x1FFF7A18);

    if (ID0 == board1.fields[0] && ID1 == board1.fields[1] && ID2 == board1.fields[2])
    {
        known = 1;
        return known;
    }
So as soon as any equality check evaluates as false the remainder of the expression is not evaluated, I suspect then that this would require less CPU cycles. If we're really concerned about overall performance of code that might be many thousands of statements, then the effect of relying on memcmp and so on might be quite detrimental especially when we factor in the cost of call/return which involves stack frame management, another cost.

One could craft a compare macro that was sophisticated enough to examine the size of the block and if a multiple of 4 or 8, then iterate over the memory blocks using an int or long pointer and compare that way, that could end up being pretty quick, I've done stuff like this before myself (on minicomputers and Windows) but its reinventing the wheel and a developer's time should ideally focus on the problem domain rather than making up for language deficiencies - IMHO !
True, a member-by-member comparison would probably be twice as efficient. In the beginning at least, when you are first "stubbing out" the program, that is when to break out that old toolbox of ugly macros...and just go to town! Once things are up and running, sure, start looking into necessary optimizations. (But if it ain't broke, don't fix it.)
 

ApacheKid

Joined Jan 12, 2015
1,118
True, a member-by-member comparison would probably be twice as efficient. In the beginning at least, when you are first "stubbing out" the program, that is when to break out that old toolbox of ugly macros...and just go to town! Once things are up and running, sure, start looking into necessary optimizations. (But if it ain't broke, don't fix it.)
Yes indeed, premature optimization is a cause of many a headache.
 
Top