1

I'm new to c development and working through a few examples for the Raspberry Pi Pico. The syntax in one example struck me as odd and thus trying to understand it in a lower-level detail.

What is the order of operations for the line *buf++ = *event_str++; within the while loop below?:

static const char *gpio_irq_str[] = {
    "LEVEL_LOW",  // 0x1
    "LEVEL_HIGH", // 0x2
    "EDGE_FALL",  // 0x4
    "EDGE_RISE"   // 0x8
};

void gpio_event_string(char *buf, uint32_t events) {
    for (uint i = 0; i < 4; i++) {
        uint mask = (1 << i);
        if (events & mask) {
            // Copy this event string into the user string
            const char *event_str = gpio_irq_str[i];
            while (*event_str != '\0') {
                *buf++ = *event_str++;
            }
            events &= ~mask;

            // If more events add ", "
            if (events) {
                *buf++ = ',';
                *buf++ = ' ';
            }
        }
    }
    *buf++ = '\0';
}

For the sake of this discussion, lets say (events & mask) == 1 when i=3 (i.e. "EDGE_RISE" case. My guess based on the end result would be:

  1. Get the address stored in pointer event_str
  2. Get the address stored in pointer buf
  3. Get the const char value ("E") stored at the address from pointer event_str
  4. Assign/Copy that const char value ("E") to the memory at the address in pointer buf
  5. Increment the address on event_str and buf
  6. Repeat 1-5 until \0 is found.

It was my understanding that the *event_str syntax evaluates to the const char value stored at address event_str, so why would *event_str++ increment the address and not the value at that address. How can you know whether the ++ increments the address in the pointer or the value stored at that pointer based on this syntax? Is there a good book/online reference for this syntax of copying strings in this way?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
topher217
  • 1,188
  • 12
  • 35
  • 1
    Since you modify different variables, the order doesn't really matter. The assignment will be done first, that's guaranteed, but which increment is done after the assignment isn't really relevant. Would it really matter if it was sequenced as `*buf = *event_str; buf += 1; event_str += 1;` or `*buf = *event_str; event_str += 1; buf += 1;`? – Some programmer dude Jan 18 '23 at 08:54
  • 1
    Or are you asking if e.g. `*buf++` is the same as `(*buf)++` or `*(buf++)`? Then it's a matter of [*operator precedence*](https://en.cppreference.com/w/c/language/operator_precedence) issue: The suffix `++` operator have higher precedence than the derefence operator so `*buf++` is `*(buf++)`. The expression `(*buf)++` would derefence the pointer to get the value it points to, and then increment the value and not the pointer. – Some programmer dude Jan 18 '23 at 09:01
  • @Someprogrammerdude, yes `operator precedence` was the term and reference I was looking for. Thanks! I will bookmark that table and try to find some other examples of confusing cases where I can interpret them based on such a table. – topher217 Jan 18 '23 at 09:10
  • 1
    This is a common FAQ. You can check for ways to implement `strcpy` and you'll most certainly find code like this. I think it originates from the K&R book. It is both bad practice and idiomatic C at once. – Lundin Jan 18 '23 at 09:11

2 Answers2

1

What is the order of operations for the line *buf++ = *event_str++; within the while loop below?:

++ has higher precedence than *. So the above statement is equivalent to:

*(buf++) = *(event_str++);

But ++, in an expression, returns the old value of its operand. So this first dereferences both the pointers, copies the contents of whatevents_str was pointing to, to the memory contents of whatbuf is pointing to, then the pointers are incremented by 1 to point to the next char in their arrays.

In a loop, this copies the memory contents of events_str to buf.

It was my understanding that the *event_str syntax evaluates to the const char value stored at address event_str, so why would *event_str++ increment the address and not the value at that address.

Because the C standard defines the precedence of ++ to be higher than *

However, that'd change if you were to add parenthesis:

(*buf)++;

This would first dereference the pointer to get the value stored at that address, and then increment that value, and not the pointer.

[1] https://en.cppreference.com/w/c/language/operator_precedence

Harith
  • 4,663
  • 1
  • 5
  • 20
1

The C language defined the precedence order of operators which determine the semantics of expressions. Postfix operators have higher precedence than prefix operators, hence *buf++ is evaluated as *(buf++). Hence the postfix operator ++ applies to the pointer, not the value it points to.

chqrlie
  • 131,814
  • 10
  • 121
  • 189