Проблема в том, что C не определяет порядок вычисления аргументов функции. Период. В большинстве случаев C не определяет порядок вычисления операндов бинарного оператора.
В результате обычно бывает ошибкой использовать и изменять переменную в одном выражении. (Для юристов по языку: Нет, я не имею в виду ошибку, которую обнаружит компилятор! Неопределенные ситуации поведения допустимы, но код по-прежнему ошибочен.)
Ваше утверждение второй версии, сокращенное, выглядит так:
printf("%p, %s, %s\n", names[l], names[l], names[l++]);
C может оценивать эти аргументы до printf()
в любом порядке. Это означает, что когда l==0
в начале размещения, любая из следующих интерпретаций этой первой итерации возможна:
printf("%p, %s, %s\n", names[0], names[0], names[0]); l+=1;
printf("%p, %s, %s\n", names[0], names[1], names[0]); l+=1;
printf("%p, %s, %s\n", names[1], names[0], names[0]); l+=1;
printf("%p, %s, %s\n", names[1], names[1], names[0]); l+=1;
На одном и том же компиляторе вы можете видеть разные порядки между отладочной и оптимизированной компиляцией. Средние две интерпретации маловероятны, но все же допускаются в компиляторе, соответствующем стандартам. Только 4-й аргумент гарантированно оценивается как names[0]', due to the definition of postfix
++ `.
Как я уже говорил выше, не используйте и не изменяйте одну и ту же переменную в одном выражении. Строго избегайте этого, когда порядок операций не гарантирован, и дважды подумайте даже в тех редких ситуациях, когда возможна только одна интерпретация. Гвидо Ван Россум (изобретатель языка Python) отмечает, что программы читаются чаще, чем пишутся. Есть определенная цена, связанная с тем, что вы запутаете другого программиста в вашей команде - или даже себя через год или два, когда вы вернетесь к редактированию кода.
Существует еще более серьезная цена, когда после тестирования компилятора начинает "проваливаться" производственный код.