0

I get a warning, not an error, and when I ignore the warning and build/run anyway, my code seems to be working just fine. I am still worried, though, because of the warning, or maybe I just want to understand it.

This function appends a single char to the beginning of a string.

void s_pfx(char pf, char *s){

    i = -1;
    while(s[++i]);
    s[i + 1] = '\0';

    while(i)
        s[i] = s[--i];

    s[i] = pf;
}

The warning is at the while loop, when I pre-decrement i. (I have i as a global variable.)

The warning is "warning: operation on 'i' may be undefined [-Wsequence-point]"

I can fix it by using

while(i){
    s[i] = s[i - 1];
    i--;
}

but why should I have to do it that way? It seems that would eat up time, nanoseconds maybe, but it will add up.

I don't understand why the compiler can't understand the code. It seems pretty well-defined to me. I looked at some of the other similar questions/answers but this seems a lot simpler.

Help! Thanks.

JosephFG
  • 3
  • 2
  • 3
    Possible duplicate of [Why are these constructs using pre and post-increment undefined behavior?](https://stackoverflow.com/questions/949433/why-are-these-constructs-using-pre-and-post-increment-undefined-behavior) – Shawn Jun 07 '19 at 02:14
  • This is one of the reasons why you don't abuse the increment and decrement operators like that. Not only is it hard to read, but you end up with undefined behavior sometimes as in this case. – eesiraed Jun 07 '19 at 02:34
  • regarding: `while(s[++i]); s[i + 1] = '\0';` Nothing in your question states that the buffer holding the passed in parameter 's[]' is (at least) one byte longer than the contained string. So this could be writing past the end of the input buffer – user3629249 Jun 07 '19 at 22:59
  • @user3629249, yes, I am keeping my eye on that. My strings are all malloc'd to 100, and I will know by my output when I need to up that. Thanks. – JosephFG Jun 23 '19 at 20:56

1 Answers1

3

The error is indeed in the expression s[i] = s[-- i].

The C specification requires that some operators act as "sequence points" — that is, that their first operand is fully evaluated before the second one. The = operator, however, is not — meaning that the compiler can evaluate the expression in any order.

This is not a problem when you do something like i = i + 3 because the left hand sign of an assignment is not evaluated (it is written to, not read). But you're using pointers there. s[i] really means *(s + i) in C; the brackets are syntax sugar.

So you really have *(s + i) = *(s + --i) in there. And that expression reads i on the left hand side (it must evaluate the sum to calculate the address where the data will be stored) and it writes to i on the right hand side (--i). And there is no fixed order of evaluation, because = is not a sequence point.

That means that the read could go before or after the write. In those cases, the C standard says that the operation is undefined, meaning that the compiler can make that branch of the code do literally anything.

aaaaaa123456789
  • 5,541
  • 1
  • 20
  • 33