rt,发现自己搞不清楚这东西,不管三七二十一先水一篇 blog 再说。
大概就是运算优先级是有括号先算括号,然后先算 ++ -- ~ !
这类一元运算符以及正负号,其次是 * / %
,再其次 + -
,再其次 << >>
,然后是 <= < >= >
,再其次 == !=
,再其次 & ^ |
,最后是 && ||
。
比如说 a=1,b=2,c=3
,那么表达式 (~a+b%c+c<<c|~b*--a<c/c&c)
的计算方式为先计算 ~a,~b,--a
,值分别为 \(-2,-3,0\),然后计算 b%c
,~b*--a
,c/c
,值分别为 \(2,0,1\),然后计算 ~a+b%c+c
,值为 \(3\),然后计算 ~a+b%c+c<<c
,值为 3<<3=24
,其次是 ~b*--a<c/c
,即 0<=1
,返回真,其次是 ~b*--a<c/c&c
,\(1\& 3=1\),最后计算 ~a+b%c+c<<c|~b*--a<c/c&c
,值为 \(25\)。
还有就是同级运算符结合的顺序,普通的运算符,譬如 + - * / % << >> & |
肯定都是从左到右计算的,譬如 a=1,b=2,c=3,d=1,e=2
,那么 a<<b<<c>>d>>e
就按照从左往右的顺序算,值为 \(4\),但是有的(一般是什么什么等于)运算符是从右往左结合的,比如说 <<= >>=
, 比方说还是 a=1,b=2,c=3,d=1,e=2
,那么 a<<=b<<=c>>=d>>=e
就先计算 d>>=e
,以此类推,最后表达式的结果为 \(65536\),\(b=16,c=3,d=0,e=2\)。
最后其实加括号完全可以避免这个问题,并且效率上也差别也不是太大,比方说
ll s=0,a=7,b=10,c=100000000,d=18,e=23;
for(int i=1;i<=1000000000;i++){
s+=a&b^++e*~d|--c;
e^=a|++d%b^!c;
} printf("%lld\n",s);
和
ll s=0,a=7,b=10,c=100000000,d=18,e=23;
for(int i=1;i<=1000000000;i++){
s+=(((a&b)^((++e)*(~d)))|(--c));
e^=((a|(++d)%b)^(!c));
} printf("%lld\n",s);
前者跑了 4.3s,后者跑了 4.5s,并且还是在运算量超大(\(10^9\))的情况下才体现出 0.2s 的差异,所以其实加括号完全可以避免这个问题。
所以我为什么要水一篇 blog 呢?