C «наблюдаемое поведение» в контексте UB «неопределенное поведение»

(Вопрос был первоначально вызван комментариями под этим ответом наЕсть ли условия гонки в этой реализации производителя-потребителя? но здесь он задается строго с точки зрения языка Си, без какого-либо параллелизма или многопоточности.)

Рассмотрим этот минимальный код:

#define BUFSIZ 10
char buf[BUFSIZ];

void f(int *pn)
{
    buf[*pn]++;
    *pn = (*pn + 1) % BUFSIZ;
}

int main()
{
    int n = 0;
    f(&n);
    return n; 
}

Вопрос: будет ли C"как будто" правила позволяют компилятору переписать код следующим образом?

void f(int *pn)
{
    int n = *pn;
    *pn = (*pn + 1) % BUFSIZ;
    buf[n]++;
}

С одной стороны, вышеизложенное не изменит наблюдаемого поведения программы в том виде, в котором оно написано.

С другой стороны,f может быть вызван с неверным индексом, возможно из другого модуля перевода:

int g()
{
    int n = -1001;
    f(&n);
}

В этом последнем случае оба варианта кода будут вызывать UB при доступе к элементу массива вне границ. Тем не менее, оригинальный код оставил бы*pn при значении, передаваемом вf (= -1001) в то время как переписанный код вступит в UB-land только после модификации*pn (в0).

Будет ли такая разница считаться «наблюдаемой» или, вернемся к фактическому вопросу, есть ли в стандарте C что-либо, что конкретно разрешало бы или исключало такой тип переписывания / оптимизации кода?

Ответы на вопрос(1)

Ваш ответ на вопрос