Операторы предварительного увеличения при использовании переменной в той же строке

Я верю, что то, что я пытаюсь сделать, вероятно, верно, потому что в обоих случаях оно разделено запятой (не типичное задание), но я точно не знаю, и поиск ничего не говорит об этих двух конкретные ситуации.

В обоих случаях я использовал переменную в качестве индекса для двух параллельных массивов.

int a[3] = {10, 20, 30};
int b[3] = {20, 40, 60};

Ситуация № 1: Инициализация структуры для массивов

struct testStruct {
int t1;
int t2;
};
int i = 0;
testStruct test = {a[++i], b[i]}

Ожидаемый результат финальной строки: test = {20, 40}

Ситуация № 2: Передача определенных значений из массивов в качестве аргументов функции

void testFunc(int t1, int t2) {
// do stuff
}
int i = 0;
test(a[++i], b[i]);

Ожидаемый результат финальной строки: test(20, 40)

Это действительный код? И если это так, действительно ли это во всех компиляторах?

Результат, который я ожидаю? Если так, это из-за массивов или из-за запятой?

Спасибо!

4

Решение

Я бы посоветовал не использовать такие «уловки» в вашем коде в долгосрочной перспективе, это кошмар обслуживания и о нем трудно рассуждать. Почти всегда есть альтернативы, например этот код:

testStruct test = {a[++i], b[i]}

может быть изменено на:

++i ;
testStruct test = {a[i], b[i]}

Таким образом, сказав, что ни в одном из этих случаев оператор запятой не используется ни в вызовах функций, ни в списках инициализации, запятая — это элементы грамматики и ничего более.

Ваша первая ситуация хорошо определена, хотя есть некоторые предостережения в зависимости от того, является ли это C ++ 11 или до C ++ 11.

В обоих случаях после каждой запятой есть точка последовательности, хотя до C ++ 11 порядок вычисления не указан. Таким образом, мы можем увидеть это для случая до C ++ 11, перейдя к дефект 430 который говорит:

Недавний отчет об ошибке GCC (
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633) спрашивает о
срок действия

int count = 23;   int foo[] = { count++, count++, count++ };

это не определено или не указано или что-то еще?

и ответ (Акцент шахты идет вперед):

Я считаю, что стандарт ясно, что каждое выражение инициализатора в
вышеизложенное является полным выражением
(1.9 [intro.execution] / 12-13; см. Также
выпуск 392) и, следовательно, после каждого
выражение (1.9 [intro.execution] / 16). я согласна с тем что стандарт делает
не похоже, чтобы диктовать порядок, в котором выражения
,
и, возможно, так и должно быть. Кто-нибудь знает компилятор, который не
оценивать выражения слева направо?

В C ++ 11 он запекается в проект стандарта C ++ 11 в разделе 8.4.5 абзац, в котором говорится:

В пределах списка инициализатора списка фигурных скобок
пункты-инициализаторы, включая те, которые являются результатом расширений пакета
(14.5.3), оцениваются в порядке их появления. То есть,
каждое значение вычисления и побочный эффект, связанный с данным
предложение initializer секвенируется перед каждым вычислением значения и
побочный эффект
связан с любым инициализатором-предложением, которое следует за ним в
разделенный запятыми список из списка инициализаторов.

Я придерживаюсь C ++ 11 в будущем, так как он не меняет ответ для остальной части контента, хотя формулировка секвенирования действительно отличается, вывод такой же.

Вторая ситуация вызывает неопределенное поведение поскольку порядок вычисления аргументов функции не определен, а их оценка неопределенно упорядочена по отношению друг к другу. Мы можем увидеть это неопределенное поведение из раздела 1.9 параграф 15 который говорит:

Если не указано иное, оценки операндов отдельных операторов
и подвыражений отдельных выражений не упорядочены. [
Примечание. В выражении, которое оценивается более одного раза в течение
выполнение программы, непоследовательное и неопределенно упорядоченное
оценки его подвыражений не должны выполняться последовательно
в разных оценках. —Конец примечания] Расчет стоимости
операнды оператора секвенируются до вычисления значения
результат оператора. Если побочный эффект на скалярном объекте
непоследовательный относительно любого другого побочного эффекта на том же скаляре
вычисление объекта или значения с использованием значения того же скаляра
объект, поведение не определено
.

и предоставляет следующий пример:

f(i = -1, i = -1); // the behavior is undefined
4

Другие решения

Первый фрагмент кода

testStruct test = {a[++i], b[i]};

допустимо (если добавить точку с запятой), потому что в соответствии со стандартом C ++

4 В списке инициализаторов списка фигурных скобок
пункты-инициализаторы, включая те, которые являются результатом расширений пакета
(14.5.3), оцениваются в порядке их появления. То есть,
каждое значение вычисления и побочный эффект, связанный с данным
предложение initializer секвенируется перед каждым вычислением значения и
побочный эффект, связанный с любым пунктом инициализатора, который следует за ним в
разделенный запятыми список из списка инициализаторов.

Примите во внимание, что компилятор GCC 4.8.1 имеет (или, по крайней мере, имел) ошибку, которую я описал

Вот
Хотя описание написано на русском языке, вы можете перевести его, используя, например, сервис goofle «translate».

Однако второй фрагмент кода

test(a[++i], b[i]);

имеет неопределенное поведение, потому что порядок вычисления аргументов функции не определен.

Вы могли бы написать вместо

test( { a[++i], b[i] } );

В этом случае выражение будет правильно сформировано.

2

По вопросам рекламы [email protected]