Можно ли предположить порядок оценки параметров функции при ее вызове в C?
Нет, это невозможно предположить, если это неопределенное поведение, то проект стандарта C99 в разделе6.5
параграфа 3
говорится:
Группировка операторов и операндов обозначается синтаксисом.74) За исключением случаев, указанных ниже (для операторов вызова функции (), &&, ||,?: И запятой), порядок оценки подвыражений и порядок возникновения побочных эффектов не указан.
В нем также говорится, за исключением случаев, указанных ниже, и конкретно сайтов function-call ()
, поэтому мы видим, что позже в проекте стандарта в разделе 6.5.2.2
Вызов функций параграф 10
говорится:
Порядок оценки указателя функции, фактических аргументов и подвыражений внутри фактических аргументов не указан, но перед фактическим вызовом есть точка последовательности.
Эта программа также демонстрирует неопределенное поведение, поскольку вы изменяете pa
более одного раза между точки последовательности. Из проекта стандарта раздела 6.5
абзаца 2
:
Между предыдущей и следующей точкой следования значение объекта должно быть изменено не более одного раза путем оценки выражения. Кроме того, предыдущее значение должно быть прочитано только для определения значения, которое будет сохранено.
он цитирует следующие примеры кода как неопределенные:
i = ++i + 1;
a[i++] = i;
Важно отметить, что хотя оператор запятой действительно вводит точки последовательности, запятая, используемая в вызовах функций, является разделитель, а не comma operator
. Если мы посмотрим на раздел 6.5.17
оператор запятой, в абзаце 2
говорится:
Левый операнд оператора запятой оценивается как недействительное выражение; после его оценки есть точка следования.
но в параграфе 3
сказано:
ПРИМЕР Как указано в синтаксисе, оператор запятой (как описано в этом подпункте) не может появляться в контекстах, где запятая используется для разделения элементов в списке (например, аргументы функций или списки инициализаторов). .
Не зная этого, включение предупреждений с gcc
с использованием хотя бы -Wall
привело бы к появлению сообщения, аналогичного следующему:
warning: operation on 'pa' may be undefined [-Wsequence-point]
printf("a[0] = %d\ta[1] = %d\ta[2] = %d\n",*(pa), *(pa++),*(++pa));
^
и по умолчанию clang
выдаст предупреждение следующим сообщением:
warning: unsequenced modification and access to 'pa' [-Wunsequenced]
printf("a[0] = %d\ta[1] = %d\ta[2] = %d\n",*(pa), *(pa++),*(++pa));
~ ^
В общем, важно понимать, как использовать ваши инструменты наиболее эффективным образом, важно знать флаги, доступные для предупреждений, gcc
вы можете найти эту информацию здесь. Некоторые полезные флаги, которые избавят вас от многих проблем в долгосрочной перспективе и являются общими для gcc
и clang
, - это -Wextra -Wconversion -pedantic
. clang
может оказаться очень полезным для понимания -fsanitize. Например, -fsanitize=undefined
обнаружит множество экземпляров неопределенного поведения во время выполнения.
person
Shafik Yaghmour
schedule
15.08.2013
pa = &a[0];
можно и нужно упростить какpa = a;
, посколькуa
распадается на указатель на свой первый элемент. - person RobertS supports Monica Cellio   schedule 10.06.2020