Другие операторы
Коллекция операторов, которые не подходят ни к одной из других основных категорий.
| Оператор | Название оператора | Пример | Описание |
|---|---|---|---|
(...) | вызов функции | f(...) | вызов функции f(), с нулем или более аргументами |
, | оператор запятая | a, b | вычислить выражение a, игнорировать его возвращаемое значение и выполнить все побочные эффекты, затем вычислить выражение b, возвращая тип и результат этого вычисления |
(type) | приведение типов | (type)a | привести тип a к типу type |
? : | условный оператор | a ? b : c | если a логически истинно (не равно нулю), то вычислить выражение b, в противном случае вычислить выражение c |
sizeof | оператор sizeof | sizeof a | размер a в байтах |
_Alignof(с C11) | оператор _Alignof | _Alignof(type) | выравнивание, требуемое для type |
typeof | операторы typeof | typeof(a) | тип a |
Вызов функции
Выражение вызова функции имеет вид
выражение ( список_аргументов (необязательно) ) |
где
| выражение | - | любое выражение типа указатель на функцию (после преобразований lvalue) |
| список_аргументов | - | список выражений, разделенных запятыми (которые не могут быть операторами запятой), любого типа полных объектов. Может быть опушен при вызове функций, не принимающих аргументы. |
Поведение выражения вызова функции зависит от того, есть ли прототип вызываемой функции в области видимости в момент вызова.
Вызов функции с прототипом
Кроме того, для каждого параметра типа массива, использующего ключевое слово static между [ и ], выражение аргумента должно обозначать указатель на элемент массива с, по крайней мере, таким же количеством элементов, как указано в выражении размера параметра. | (с C99) |
- если есть параметр с эллипсисом, по умолчанию выполняются повышения аргументов для оставшихся аргументов, которые предоставляются
va_list.
void f(char* p, int x) {}
int main(void)
{
f("abc", 3.14); // array to pointer and float to int conversions
} Вызов функции без прототипа1) Аргументы вычисляются в неопределенном порядке и без последовательности. 2) По умолчанию выполняются повышения аргументов для каждого выражения аргумента. 3) Присваивание выполняется для копирования значения каждого аргумента в соответствующий параметр функции, игнорируя любые квалификаторы типа в типе параметра и его потенциально рекурсивных элементов или членов, если таковые имеются. 4) Функция выполняется, и возвращаемое ею значение становится значением выражения вызова функции (если функция возвращает void, выражение вызова функции является выражением void)void f(); // no prototype
int main(void)
{
f(1, 1.0f); // UB unless f is defined to take an int and a double
}
void f(int a, double c) {}Поведение вызова функции без прототипа является неопределенным, если
| (до C23) |
Примечания
Вычисления выражения, обозначающего вызываемую функцию, и всех аргументов, не упорядочены друг с другом (но существует точка последовательности перед началом выполнения тела функции)
(*pf[f1()]) (f2(), f3() + f4()); // f1, f2, f3, f4 may be called in any order
Хотя вызов функции определен только для указателей на функции, он работает и с указателями на функции благодаря неявной конверсии функция-в-указатель.
int f(void) { return 1; }
int (*pf)(void) = f;
int main(void)
{
f(); // convert f to pointer, then call
(&f)(); // create a pointer to function, then call
pf(); // call the function
(*pf)(); // obtain the function designator, convert to pointer, then calls
(****f)(); // convert to pointer, obtain the function, repeat 4x, then call
(****pf)(); // also OK
}Функции, которые игнорируют неиспользуемые аргументы, такие как printf, должны вызываться с прототипом в области видимости (прототип таких функций обязательно использует параметр с эллипсисом), чтобы избежать вызова неопределенного поведения.
Текущая формулировка стандарта по подготовке параметров функции некорректна, потому что она указывает, что параметры присваиваются из аргументов во время вызова, что неверно отвергает параметры или члены типа с квалификатором const и некорректно применяет семантику volatile, которая не может быть реализована для параметров функции на многих платформах. Отчет о дефекте после C11 DR427 предложил изменить такую семантику с присваивания на инициализацию, но он был закрыт как не-дефект.
| Выражение вызова функции, где выражение состоит только из идентификатора, и этот идентификатор не объявлен, ведет себя так, как если бы идентификатор был объявлен как extern int identifier(); // returns int and has no prototype Таким образом, следующая полная программа является допустимым C89: main()
{
int n = atoi("123"); // implicitly declares atoi as int atoi()
} | (до C99) |
Оператор запятая
Выражение оператора запятой имеет вид
левое_операнд , правое_операнд |
где
| левое_операнд | - | любое выражение |
| правое_операнд | - | любое выражение, кроме другого оператора запятой (другими словами, ассоциативность оператора запятой слева направо) |
Сначала вычисляется левое операнд, левое_операнд, и его результат отбрасывается.
Затем происходит точка последовательности, так что все побочные эффекты левое_операнд завершены.
Затем вычисляется правое операнд, правое_операнд, и его результат возвращается оператором запятой как не-lvalue.
Примечания
Тип левое_операнд может быть void (то есть, это может быть вызов функции, возвращающей void, или это может быть выражение, приведенное к void).
Оператор запятая может быть lvalue в C++, но никогда в C
Оператор запятой может возвращать структуру (единственные другие выражения, которые возвращают структуры, - это составные литералы, вызовы функций, присваивания и условный оператор)
В следующих контекстах оператор запятой не может появляться на верхнем уровне выражения, потому что запятая имеет другое значение:
- список аргументов в вызове функции
- выражение инициализации или список инициализации
- обобщенное выбор
Если оператор запятой должен быть использован в таком контексте, он должен быть заключен в скобки:
// int n = 2,3; // error, comma assumed to begin the next declarator
// int a[2] = {1,2,3}; // error: more initializers than elements
int n = (2,3), a[2] = {(1,2),3}; // OK
f(a, (t=3, t+2), c); // OK, first, stores 3 in t, then calls f with three argumentsОператор запятой на верхнем уровне также запрещён в границах массива
// int a[2,3]; // error int a[(2,3)]; // OK, VLA array of size 3 (VLA because (2,3) is not a constant expression)
Оператор запятой не разрешён в постоянных выражениях, независимо от того, находится он на верхнем уровне или нет
// static int n = (1,2); // Error: constant expression cannot call the comma operator
Оператор приведения типа
Условный оператор
Выражение условного оператора имеет вид
условие ? выражение-истина : выражение-ложь |
где
| условие | - | выражение скалярного типа |
| выражение-истина | - | выражение, которое будет вычислено, если условие не равно нулю |
| выражение-ложь | - | выражение, которое будет вычислено, если условие равно нулю |
Разрешены только следующие выражения в качестве выражение-истина и выражение-ложь
- два выражения любого арифметического типа
- два выражения одного и того же типа структуры или объединения
- два выражения типа void
- два указателя на типы, совместимые, игнорируя cvr-квалификаторы
| (с C23) |
- одно выражение — указатель, другое — константа нулевого указателя (например,
NULL)или значениеnullptr_t(с C23) - одно выражение — указатель на объект, другое — указатель на void (возможно, с квалификаторами)
nullptr_t(с C23), тип — тип этого указателя
const int*, а другой — volatile int*, результатом является const volatile int*), и если типы различались, тип указываемого объекта — составной тип. 7) если оба имеют тип nullptr_t , общий тип также nullptr_t | (с C23) |
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1))) // if x is an Integer Constant Expression then macro expands to sizeof(*(1 ? NULL : (int *) 1)) // (void *)((x)*0l)) -> NULL // according to point (4) this further converts into sizeof(int) // if x is not an Integer Constant Expression then macro expands to // according to point (6) (sizeof(*(void *)(x)) // Error due incomplete type
Примечания
Условный оператор никогда не является выражением-ссылкой, хотя может возвращать объекты типа структура/объединение. Единственными другими выражениями, которые могут возвращать структуры, являются присваивание, оператор запятой, вызов функции и литерал составного типа.
Обратите внимание, что в C++ он может быть выражением-ссылкой.
См. приоритет операторов для получения подробностей о взаимном приоритете этого оператора и присваивания.
Условный оператор имеет ассоциативность справа налево, что позволяет цепочку
#include <assert.h>
enum vehicle { bus, airplane, train, car, horse, feet };
enum vehicle choose(char arg)
{
return arg == 'B' ? bus :
arg == 'A' ? airplane :
arg == 'T' ? train :
arg == 'C' ? car :
arg == 'H' ? horse :
feet ;
}
int main(void)
{
assert(choose('H') == horse && choose('F') == feet);
} Оператор sizeof
См. оператор sizeof
Оператор _Alignof
Операторы typeof
См. операторы typeof
Ссылки
- Стандарт C23 (ISO/IEC 9899:2023):
- 6.5.2.2 Вызовы функций (с. TBD)
- 6.5.3.4 Операторы sizeof и _Alignof (с. TBD)
- 6.5.4 Операторы приведения типа (с. TBD)
- 6.5.15 Условный оператор (с. TBD)
- 6.5.17 Оператор запятой (с. TBD)
- 6.7.3.5 Спецификаторы typeof (с. 115-118)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.5.2.2 Вызовы функций (с. 58-59)
- 6.5.3.4 Операторы sizeof и _Alignof (с. 64-65)
- 6.5.4 Операторы приведения типа (с. 65-66)
- 6.5.15 Условный оператор (с. 71-72)
- 6.5.17 Оператор запятой (с. 75)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.5.2.2 Вызовы функций (с. 81-82)
- 6.5.3.4 Операторы sizeof и _Alignof (с. 90-91)
- 6.5.4 Операторы приведения типа (с. 91)
- 6.5.15 Условный оператор (с. 100)
- 6.5.17 Оператор запятой (с. 105)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.5.2.2 Вызовы функций (с. 71-72)
- 6.5.3.4 Оператор sizeof (с. 80-81)
- 6.5.4 Операторы приведения типа (с. 81)
- 6.5.15 Условный оператор (с. 90-91)
- 6.5.17 Оператор запятой (с. 94)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.3.2.2 Вызовы функций
- 3.3.3.4 Оператор sizeof
- 3.3.4 Операторы приведения типа
- 3.3.15 Условный оператор
- 3.3.17 Оператор запятой
См. также
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| присваивание | инкремент декремент | арифметические | логические | сравнения | доступ к членам структуры | другие |
|
|
|
|
|
|
|
|
| Документация C++ для других операторов |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/operator_other