Namespaces
Variants

Other operators

From cppreference.net

Набор операторов, которые не подходят ни к одной из других основных категорий.

Оператор Название оператора Пример Описание
( ... ) вызов функции 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

Содержание

Вызов функции

Выражение вызова функции имеет вид

expression ( argument-list  (необязательно) )

где

expression - любое выражение типа указатель-на-функцию (после lvalue conversions )
argument-list - разделённый запятыми список выражений (которые не могут быть операторами запятой) любого полного объектного типа. Может быть опущен при вызове функций, которые не принимают аргументов.

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

Вызов функции с прототипом

1) Количество параметров должно равняться количеству аргументов (если не используется параметр с многоточием).
2) Тип каждого параметра должен быть таким, чтобы неявное преобразование как при присваивании существовало для преобразования неквалифицированного типа соответствующего аргумента в тип параметра.
Кроме того, для каждого параметра массива , который использует ключевое слово static между [ и ] , выражение аргумента должно указывать на указатель на элемент массива, содержащего как минимум столько элементов, сколько указано в выражении размера параметра.
(начиная с C99)
4) Assignment выполняется для копирования значения каждого аргумента в соответствующий параметр функции, игнорируя любые квалификаторы типа в типе параметра и его возможно рекурсивных элементах или членах, если таковые имеются (примечание: функция может изменять свои параметры, и эти изменения не влияют на аргументы; вызовы функций в C являются только вызовами по значению).
  • если присутствует trailing ellipsis параметр, Default argument promotions выполняются на оставшихся аргументах, которые становятся доступными для va_list .
5) Функция выполняется, и возвращаемое ей значение становится значением выражения вызова функции (если функция возвращает void, выражение вызова функции является void-выражением)
void f(char* p, int x) {}
int main(void)
{
    f("abc", 3.14); // array to pointer and float to int conversions
}

Вызов функции без прототипа

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) {}

Поведение вызова функции без прототипа является неопределенным, если

  • количество аргументов не соответствует количеству параметров.
  • продвинутые типы аргументов не совместимы с продвинутыми типами параметров, за исключением случаев, когда
  • знаковые и беззнаковые версии одного и того же целочисленного типа считаются совместимыми, если значение аргумента представимо обоими типами.
  • указатели на void и указатели на (возможно cvr-квалифицированные) символьные типы считаются совместимыми
(до C23)

Примечания

Вычисления expression , которое обозначает вызываемую функцию, и всех аргументов являются неупорядоченными относительно друг друга (но существует точка следования перед началом выполнения тела функции)

(*pf[f1()]) (f2(), f3() + f4()); // функции f1, f2, f3, f4 могут быть вызваны в произвольном порядке

Хотя вызов функции определён только для указателей на функции, он работает с обозначениями функций благодаря неявному преобразованию функции в указатель .

int f(void) { return 1; }
int (*pf)(void) = f;
int main(void)
{
    f();    // преобразование f в указатель, затем вызов
    (&f)(); // создание указателя на функцию, затем вызов
    pf();    // вызов функции
    (*pf)(); // получение обозначения функции, преобразование в указатель, затем вызов
    (****f)(); // преобразование в указатель, получение функции, повтор 4 раза, затем вызов
    (****pf)(); // также корректно
}

Функции, которые игнорируют неиспользуемые аргументы, такие как printf , должны вызываться с прототипом в области видимости (прототип таких функций обязательно использует завершающее многоточие параметр), чтобы избежать вызова неопределенного поведения.

Текущая стандартная формулировка семантики подготовки параметров функции является дефектной, поскольку она указывает, что параметры присваиваются из аргументов при вызове, что ошибочно отвергает const-квалифицированные типы параметров или членов и неуместно применяет семантику volatile, которая нереализуема для параметров функции на многих платформах. Пост-C11 отчёт о дефекте DR427 предложил изменение такой семантики с присваивания на инициализацию, но был закрыт как не-дефект.

Выражение вызова функции, в котором expression состоит исключительно из идентификатора и этот идентификатор не объявлен, действует так, как если бы идентификатор был объявлен как

extern int identifier(); // returns int and has no prototype

Таким образом, следующая полная программа является корректной C89:

main()
{
    int n = atoi("123"); // implicitly declares atoi as int atoi()
}
(до C99)

Оператор запятая

Выражение с оператором запятой имеет вид

lhs , rhs

где

lhs - любое выражение
rhs - любое выражение, кроме другого оператора запятой (другими словами, ассоциативность оператора запятой является левосторонней)

Сначала вычисляется левый операнд, lhs , и его результирующее значение отбрасывается.

Затем происходит точка следования , так что все побочные эффекты lhs завершаются.

Затем вычисляется правый операнд, rhs , и его результат возвращается оператором запятой как не-lvalue .

Примечания

Тип lhs может быть void (то есть это может быть вызов функции, возвращающей void , или выражение с приведением типа к void )

Оператор запятая может быть lvalue в C++, но никогда в C

Оператор запятая может возвращать структуру (единственными другими выражениями, возвращающими структуры, являются составные литералы, вызовы функций, присваивания и условный оператор)

В следующих контекстах оператор запятой не может находиться на верхнем уровне выражения, поскольку запятая имеет другое значение:

Если оператор запятой должен использоваться в таком контексте, он должен быть заключен в скобки:

// int n = 2,3; // ошибка: запятая предполагает начало следующего декларатора
// int a[2] = {1,2,3}; // ошибка: больше инициализаторов, чем элементов
int n = (2,3), a[2] = {(1,2),3}; // OK
f(a, (t=3, t+2), c); // OK: сначала сохраняет 3 в t, затем вызывает f с тремя аргументами

Оператор запятой верхнего уровня также запрещен в границах массива

// int a[2,3]; // ошибка
int a[(2,3)]; // OK, VLA массив размера 3 (VLA, потому что (2,3) не является константным выражением)

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

// static int n = (1,2); // Ошибка: константное выражение не может вызывать оператор запятой

Оператор приведения

См. cast operator

Условный оператор

Выражение условного оператора имеет вид

условие ? выражение-истина : выражение-ложь

где

condition - выражение скалярного типа
expression-true - выражение, которое будет вычислено, если condition не равно нулю
expression-false - выражение, которое будет вычислено, если condition равно нулю

Только следующие выражения разрешены в качестве expression-true и expression-false

(начиная с C23)
  • одно выражение является указателем, а другое — константой нулевого указателя (такой как NULL ) или значением типа nullptr_t (начиная с C23)
  • одно выражение является указателем на объект, а другое — указателем на void (возможно, с квалификаторами)
1) Сначала вычисляется condition . После этого вычисления присутствует точка следования .
2) Если результат condition не равен нулю, выполняется expression-true , в противном случае выполняется expression-false
3) Выполняет преобразование результата вычисления к общему типу , определяемому следующим образом:
1) если выражения имеют арифметический тип, общий тип является типом после usual arithmetic conversions
2) если выражения имеют тип структуры/объединения, общим типом является этот тип структуры/объединения
3) если оба выражения являются void, всё условное операторное выражение является void-выражением
4) если один операнд является указателем, а другой — константой нулевого указателя или значением типа nullptr_t (начиная с C23) , результирующий тип соответствует типу этого указателя
5) если оба являются указателями, результатом будет указатель на тип, объединяющий cvr-квалификаторы обоих указываемых типов (то есть, если один - это const int * , а другой - volatile int * , результатом будет const volatile int * ), и если типы были различными, указываемый тип является составным типом .
6) если один из указателей является указателем на void, результат представляет собой указатель на void с объединенными cvr-квалификаторами
7) если оба имеют тип nullptr_t , общий тип также является nullptr_t
(since C23)
#define ICE(x) (sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))
// если x является целочисленным константным выражением, то макрос раскрывается в
sizeof(*(1 ? NULL : (int *) 1))  // (void *)((x)*0l)) -> NULL
// согласно пункту (4) это далее преобразуется в
sizeof(int)
// если x не является целочисленным константным выражением, то макрос раскрывается
// согласно пункту (6)
(sizeof(*(void *)(x))           // Ошибка из-за неполного типа

Примечания

Условный оператор никогда не является lvalue выражением , хотя он может возвращать объекты структурного/объединенного типа. Единственными другими выражениями, которые могут возвращать структуры, являются присваивание , оператор запятая , вызов функции и составной литерал .

Обратите внимание, что в C++ это может быть lvalue-выражение.

См. приоритет операторов для получения подробной информации об относительном приоритете этого оператора и присваивания.

Условный оператор имеет правостороннюю ассоциативность, что позволяет создавать цепочки

#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 operator

_Alignof оператор

См. _Alignof operator

typeof операторы

См. typeof operators

Ссылки

  • Стандарт C23 (ISO/IEC 9899:2024):
  • 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 Оператор запятая

Смотрите также

Общие операторы
присваивание инкремент
декремент
арифметические логические сравнения доступа к членам
доступа
другие

a = b
a + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b

a [ b ]
* a
& a
a - > b
a. b

a ( ... )
a, b
( type ) a
a ? b : c
sizeof


_Alignof
(начиная с C11)
(до C23)

alignof
(начиная с C23)

C++ documentation для Other operators