?
? ????? PHP ??? ???? ??? ?? ??
算術(shù)運算符將標(biāo)準(zhǔn)的數(shù)學(xué)運算應(yīng)用于其操作數(shù)。
Operator | Operator name | Example | Result |
---|---|---|---|
+ | unary plus | +a | the value of a after promotions |
- | unary minus | -a | the negative of a |
+ | addition | a + b | the addition of a and b |
- | subtraction | a - b | the subtraction of b from a |
* | product | a * b | the product of a and b |
/ | division | a / b | the division of a by b |
% | modulo | a % b | the remainder of a divided by b |
~ | bitwise NOT | ~a | the bitwise NOT of a |
& | bitwise AND | a & b | the bitwise AND of a and b |
| | bitwise OR | a | b | the bitwise OR of a and b |
^ | bitwise XOR | a ^ b | the bitwise XOR of a and b |
<< | bitwise left shift | a << b | a left shifted by b |
bitwise right shift | a >> b | a right shifted by b |
無符號整數(shù)運算總是以模2n 來執(zhí)行
其中 n 是該特定整數(shù)中的位數(shù)。例如unsigned int
,添加一個UINT_MAX
給出0
,并從0
給出中減去一個UINT_MAX
。
當(dāng)有符號整數(shù)算術(shù)運算溢出(結(jié)果不適合結(jié)果類型)時,行為是未定義的:它可能會根據(jù)表示規(guī)則(通常是2的補碼)進行回繞,它可能陷入某些平臺或由于編譯器選項(例如-ftrapv
在 GCC 和 Clang中),或者可以由編譯器完全優(yōu)化。
如果 #pragma STDC FENV_ACCESS
設(shè)置為ON
,所有浮點算術(shù)運算符服從當(dāng)前浮點舍入方向并報告 math_errhandling 中指定的浮點算術(shù)錯誤,除非部分靜態(tài)初始化程序(在這種情況下不引發(fā)浮點異常并舍入)模式是最近的)。
除非#pragma STDC FP_CONTRACT
設(shè)置為OFF
,否則 所有浮點運算都可以像中間結(jié)果具有無限范圍和精度一樣執(zhí)行,即忽略舍入錯誤和浮點異常(如果表達式完全按寫入方式計算)時可以觀察到的優(yōu)化。例如,允許(x*y) + z
使用單個融合乘加CPU指令或優(yōu)化a = x*x*x*x;
as執(zhí)行tmp = x*x; a = tmp*tmp
。
與浮點運算無關(guān),浮點運算的中間結(jié)果的范圍和精度可能與其類型所指示的不同,請參閱FLT_EVAL_METHOD
。
一元算術(shù)運算符表達式具有這種形式。
| (1) | |
---|---|---|
| (2) |
1)一元加(促銷)
2)一元減號(否定)
其中
expression | - | expression of any arithmetic type |
---|
一元加號和一元減號首先將積分促銷應(yīng)用于它們的操作數(shù),然后。
一元加值返回提升后的值
一元減號返回提升后的值的負數(shù)(除了 NaN 的負數(shù)是另一個 NaN)
表達式的類型是升級后的類型,值類別是非左值。
當(dāng)應(yīng)用于,或在典型(2的補碼)平臺上時INT_MIN
,由于有符號整數(shù)溢出,一元減法調(diào)用未定義的行為。LONG_MINLLONG_MIN
在 C ++中,一元運算符+也可以與其他內(nèi)置類型(如數(shù)組和函數(shù))一起使用,而在 C 中則不是這樣。
#include <stdio.h>#include <complex.h>int main(void){ char c = 'a'; printf("sizeof char: %zu sizeof int: %zu\n", sizeof c, sizeof +c); printf("-1, where 1 is signed: %d\n", -1); printf("-1, where 1 is unsigned: %u\n", -1u); double complex z = 1 + 2*I; printf("-(1+2i) = %.1f%+.1f\n", creal(-z), cimag(-z));}
可能的輸出:
sizeof char: 1 sizeof int: 4-1, where 1 is signed: -1-1, where 1 is unsigned: 4294967295-(1+2i) = -1.0-2.0
二元附加算術(shù)運算符表達式具有這種形式。
lhs + rhs | (1) | |
---|---|---|
lhs - rhs | (2) |
1)另外:lhs 和 rhs 必須是以下之一
都有算術(shù)類型,包括復(fù)雜和想象
一個是完成對象類型的指針,另一個是整數(shù)類型
2)減法:lhs 和 rhs 必須是以下之一
都有算術(shù)類型,包括復(fù)雜和想象
lhs具有完成對象類型的指針,rhs具有整數(shù)類型
都是指向兼容類型的完整對象的指針,忽略限定符
如果兩個操作數(shù)都有算術(shù)類型,那么。
首先,執(zhí)行通常的算術(shù)轉(zhuǎn)換
然后,按照通常的數(shù)學(xué)規(guī)則(對于減法,將rhs從lhs中減去),對轉(zhuǎn)換后的操作數(shù)的值進行相加或相減,除了
如果一個操作數(shù)是 NaN,那么結(jié)果是NaN
無窮大減去無窮大是 NaN 并且FE_INVALID
被提升
無限加上負的無窮大是 NaN 并且FE_INVALID
被提升
復(fù)數(shù)和虛數(shù)加法和減法的定義如下(注意,如果兩個操作數(shù)都是虛數(shù),則結(jié)果類型為虛數(shù),如果一個操作數(shù)是實數(shù)而另一個虛數(shù),則如通常的算術(shù)轉(zhuǎn)換所指定的那樣):
| u | iv | u + iv |
---|---|---|---|
x | x ± u | x ± iv | (x ± u) ± iv |
iy | ±u + iy | i(y ± v) | ±u + i(y ± v) |
x + iy | (x ± u) + iy | x + i(y ± v) | (x ± u) + i(y ± v) |
// work in progress// note: take part of the c/language/conversion example
如果指針P
指向具有索引的數(shù)組的元素I
,則
P+N
并且N+P
是指向具有索引的相同數(shù)組的元素的指針I+N
P-N
是一個指向索引{tt | IN}}的相同數(shù)組元素的指針
只有在原始指針和結(jié)果指針都指向同一數(shù)組的元素或超過該數(shù)組的末尾時,才會定義行為。請注意,當(dāng)p指向數(shù)組的第一個元素時執(zhí)行p-1是未定義的行為,并可能在某些平臺上失敗。
如果指針P1
指向一個數(shù)組中的索引I
(或者一個超過末尾的數(shù)組)P2
的元素并且指向具有索引的相同數(shù)組的元素J
(或者指向末尾的一個元素),那么
P1-P2
具有等于的值J-I
和類型ptrdiff_t
(這是一個有符號的整數(shù)類型,通常是可以聲明的最大對象的大小的一半)
The behavior is defined only if the result fits in ptrdiff_t
.
為了進行指針運算,指向不是任何數(shù)組元素的對象的指針將被視為指向大小為1的數(shù)組的第一個元素的指針。
// work in progressint n = 4, m = 3;int a[n][m]; // VLA of 4 VLAs of 3 ints eachint (*p)[m] = a; // p == &a[0] p = p + 1; // p == &a[1] (pointer arithmetic works with VLAs just the same)(*p)[2] = 99; // changes a[1][2]
二進制乘法算術(shù)運算符表達式具有這種形式。
lhs * rhs | (1) | |
---|---|---|
lhs / rhs | (2) | |
lhs % rhs | (3) |
1)乘法。lhs 和 rhs 必須有算術(shù)類型
2)division。lhs 和 rhs 必須有算術(shù)類型
3)余數(shù)。lhs 和 rhs 必須具有整數(shù)類型
首先,執(zhí)行通常的算術(shù)轉(zhuǎn)換。然后...
二進制運算符*在通常的算術(shù)定義之后執(zhí)行其操作數(shù)的乘法(在通常的算術(shù)轉(zhuǎn)換之后),除此之外。
如果一個操作數(shù)是 NaN,則結(jié)果是 NaN
如果無窮大乘以零,就會產(chǎn)生NaN并被FE_INVALID
提升
無窮乘以非零乘法給無窮(即使對于復(fù)雜的參數(shù))
因為在C中,任何具有至少一個無限部分的復(fù)數(shù)值作為無窮大,即使其另一部分是NaN,通常的算術(shù)規(guī)則也不適用于復(fù)數(shù)復(fù)數(shù)乘法。浮點操作數(shù)的其他組合遵循下表:
* | u | iv | u + iv |
---|---|---|---|
x | xu | i(xv) | (xu) + i(xv) |
iy | i(yu) | ?yv | (?yv) + i(yu) |
x + iy | (xu) + i(yu) | (?yv) + i(xv) | special rules |
除無限處理外,不允許復(fù)數(shù)乘法溢出中間結(jié)果,除非 #pragma STDC CX_LIMITED_RANGE
設(shè)置為ON
,在這種情況下,可以按照(x + iy)×(u + iv)=(xu-yv)+ i (yu + xv),因為程序員承擔(dān)限制操作數(shù)范圍和處理無窮大的責(zé)任。
盡管不允許不適當(dāng)?shù)囊绯?,但?fù)雜的乘法可能會引發(fā)虛假的浮點異常(否則實現(xiàn)非溢出版本非常困難)。
除了那個之外,二元運算符/第一操作數(shù)除以第二操作數(shù)(在通常的算術(shù)轉(zhuǎn)換之后)遵循通常的算術(shù)定義。
當(dāng)通常的算術(shù)轉(zhuǎn)換后的類型是一個整數(shù)類型時,結(jié)果是代數(shù)商(不是分數(shù)),在實現(xiàn)定義的方向上舍入(直到C99)向零截斷(因為C99)
如果一個操作數(shù)是NaN,則結(jié)果是NaN
如果第一個操作數(shù)是復(fù)數(shù)無窮大,第二個操作數(shù)是有限的,那么
/運算符的結(jié)果是一個復(fù)雜的無窮大。
如果第一個操作數(shù)是有限的,第二個操作數(shù)是一個復(fù)數(shù)的無窮大,那么
/運算符的結(jié)果是零。
因為在C中,任何具有至少一個無限部分的復(fù)數(shù)值作為無窮大,即使其另一部分是NaN,通常的算術(shù)規(guī)則也不適用于復(fù)數(shù)復(fù)數(shù)除法。浮點操作數(shù)的其他組合遵循下表:
/ | u | iv |
---|---|---|
x | x/u | i(?x/v) |
iy | i(y/u) | y/v |
x + iy | (x/u) + i(y/u) | (y/v) + i(?x/v) |
除無限處理外,復(fù)數(shù)除法不允許溢出中間結(jié)果,除非 #pragma STDC CX_LIMITED_RANGE
設(shè)置為ON
,在這種情況下,可以按照(x + iy)/(u + iv)=(xu + yv)+ i (宇-15)/(U2
+ v2
),因為程序員承擔(dān)限制操作數(shù)范圍和處理無窮大的責(zé)任。
盡管不允許不適當(dāng)?shù)囊绯?,?fù)雜的劃分可能會引發(fā)虛假的浮點異常(否則實現(xiàn)非溢出版本非常困難)。
如果第二個操作數(shù)為零,則行為是未定義的,但是如果支持 IEEE 浮點算術(shù)并且發(fā)生浮點除法,那么。
將非零數(shù)字除以±0.0會給出正確符號的無窮大,并將FE_DIVBYZERO
其升高
將0.0除0.0得到NaN并FE_INVALID
升高
二元運算符%產(chǎn)生第一個操作數(shù)除以第二個操作數(shù)的其余部分(在通常的算術(shù)轉(zhuǎn)換后)。
余數(shù)的符號是這樣定義的,即如果商a/b
可以在結(jié)果類型中表示,那么(a/b)*b + a%b == a
。
如果第二個操作數(shù)為零,則行為未定義。
如果商a/b
不能在結(jié)果類型可表示,雙方的行為a/b
,并a%b
沒有定義(這意味著INT_MIN%-1
是未定義2的補數(shù)系統(tǒng))。
注意:余數(shù)運算符不適用于浮點類型,庫函數(shù)fmod
提供該功能。
#include<stdio.h>#include <stdio.h>#include <complex.h>#include <math.h>int main(void){ // TODO simpler cases, take some from C++ double complex z = (1 + 0*I) * (INFINITY + I*INFINITY);// textbook formula would give// (1+i0)(∞+i∞) ? (1×∞ – 0×∞) + i(0×∞+1×∞) ? NaN + I*NaN// but C gives a complex infinity printf("%f + i*%f\n", creal(z), cimag(z)); // textbook formula would give// cexp(∞+iNaN) ? exp(∞)×(cis(NaN)) ? NaN + I*NaN// but C gives ±∞+i*nan double complex y = cexp(INFINITY + I*NAN); printf("%f + i*%f\n", creal(y), cimag(y)); }
可能的輸出:
inf + i*inf inf + i*nan
按位算術(shù)運算符表達式具有這種形式。
~ rhs | (1) | |
---|---|---|
lhs & rhs | (2) | |
lhs | rhs | (3) | |
lhs ^ rhs | (4) |
1) bitwise NOT
2) bitwise AND
3) bitwise OR
4) bitwise XOR
其中
lhs, rhs | - | expressions of integer type |
---|
首先,運營商&,^和| 對兩個操作數(shù)執(zhí)行通常的算術(shù)轉(zhuǎn)換操作符?對其唯一的操作數(shù)執(zhí)行整數(shù)提升。
然后,相應(yīng)的二進制邏輯運算符按位進行應(yīng)用; 也就是說,根據(jù)邏輯操作(NOT,AND,OR 或 XOR)將結(jié)果的每一位置1或清零,并將其應(yīng)用于操作數(shù)的相應(yīng)位。
注意:位運算符通常用于操作位集和位掩碼。
注意:對于無符號類型(推廣后),表達式?E等于結(jié)果類型可表示的最大值減去E的原始值。
#include <stdio.h>#include <stdint.h>int main(void){ uint16_t mask = 0x00f0; uint32_t a = 0x12345678; printf("Value: %#x mask: %#x\n" "Setting bits: %#x\n" "Clearing bits: %#x\n" "Selecting bits: %#x\n", a,mask,(a|mask),(a&~mask),(a&mask));}
可能的輸出:
Value: 0x12345678 mask: 0xf0Setting bits: 0x123456f8Clearing bits: 0x12345608Selecting bits: 0x70
按位移運算符表達式具有這種形式。
lhs << rhs | (1) | |
---|---|---|
lhs >> rhs | (2) |
1)左移 rhs 位
2)通過 rhs 位右移 lhs
其中
lhs, rhs | - | expressions of integer type |
---|
首先,對每個操作數(shù)單獨執(zhí)行整數(shù)升級(注意:這不同于其他二進制算術(shù)運算符,它們都執(zhí)行常規(guī)算術(shù)轉(zhuǎn)換)。結(jié)果的類型是促銷后的 lhs 類型。
對于無符號的 lhs,其值LHS << RHS
是 LHS * 2RHS 的值
返回類型的模數(shù)最大值減1加(即,執(zhí)行按位左移,并且丟棄從目標(biāo)類型移出的位)。對于有符號的 lhs,其值為LHS << RHS
LHS * 2RHS
如果它在升級類型的 lhs 中可表示,否則行為是未定義的。
對于無符號的 lhs 和帶有非負值的帶符號的 lhs,其值LHS >> RHS
是 LHS / 2RHS 的整數(shù)部分
對于負數(shù)LHS
,值LHS >> RHS
是實現(xiàn)定義的,在大多數(shù)實現(xiàn)中,這將執(zhí)行算術(shù)右移(以便結(jié)果保持負值)。因此,在大多數(shù)實現(xiàn)中,向右移位一個符號LHS
將使用原始符號位填充新的較高位(即,如果它是非負的則為0,如果是負的則為0)。
在任何情況下,如果 rhs 為負數(shù)或者大于或等于升級的 lhs 中的位數(shù),則行為是不確定的。
#include <stdio.h>enum {ONE=1, TWO=2};int main(void){ char c = 0x10; unsigned long long ulong_num = 0x123; printf("0x123 << 1 = %#llx\n" "0x123 << 63 = %#llx\n" // overflow truncates high bits for unsigned numbers "0x10 << 10 = %#x\n", // char is promoted to int ulong_num << 1, ulong_num << 63, c << 10); long long long_num = -1000; printf("-1000 >> 1 = %lld\n", long_num >> ONE); // implementation defined}
可能的輸出:
0x123 << 1 = 0x2460x123 << 63 = 0x80000000000000000x10 << 10 = 0x4000-1000 >> 1 = -500