В C, если B является изменчивым, должно ли выражение (void) (B = 1) читать B

Я работаю над компиляторами для нескольких встроенных платформ. Пользователь недавно пожаловался на следующее поведение одного из наших компиляторов. Данный код выглядит так:

extern volatile int MY_REGISTER;

void Test(void)
{
    (void) (MY_REGISTER = 1);
}

Компилятор генерирует это (на псевдоассемблере):

Test:
    move regA, 1
    store regA, MY_REGISTER
    load regB, MY_REGISER

То есть он не только записывает в MY_REGISTER, но и затем считывает его обратно. Дополнительная нагрузка расстроила его по соображениям производительности. Я объяснил, что это произошло потому, что в соответствии со стандартом «выражение присваивания имеет значение левого операнда после присваивания, [...]» .

Как ни странно, удаление приведенного к пустоте меняет поведение: исчезает нагрузка. Пользователь доволен, но я просто сбит с толку.

Я также проверил это в паре версий GCC (3.3 и 4.4). Там компилятор никогда не генерирует нагрузку, даже если значение используется явно, например

int TestTwo(void)
{
    return (MY_REGISTER = 1);
}

Превращается в

TestTwo:
    move regA, 1
    store regA, MY_REGISTER
    move returnValue, 1
    return

Есть ли у кого-нибудь мнение о том, какая интерпретация стандарта является правильной? Должен ли вообще происходить обратный отсчет? Правильно или полезно добавлять только чтение, если значение используется или приводится к void?

13
задан Ned 28 February 2011 в 10:31
поделиться