Re: [問題] while(*s++ = *t++ );疑問
※ 引述《BitTorrent (螳勃唬)》之銘言:
: 請問一下
: strcpy 中
: while( *s++ = *t++);
: 可以copy char arrays
: 想請問一下可是++ 優先權 不是大於*
: 所以照理講第一個不會被複製到阿?
推
06/28 12:58,
06/28 12:58
這裡其實我覺得優先權不是指誰先做誰後做,而是指一個運算式該怎麼被我們解讀
(後面修文補完文章內容)
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.225.46.73
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1435482334.A.2D2.html
→
06/28 17:06, , 1F
06/28 17:06, 1F
→
06/28 18:08, , 2F
06/28 18:08, 2F
推
06/28 19:14, , 3F
06/28 19:14, 3F
→
06/28 19:15, , 4F
06/28 19:15, 4F
→
06/28 19:16, , 5F
06/28 19:16, 5F
→
06/28 19:27, , 6F
06/28 19:27, 6F
→
06/28 19:44, , 7F
06/28 19:44, 7F
→
06/28 19:45, , 8F
06/28 19:45, 8F
推
06/28 20:11, , 9F
06/28 20:11, 9F
→
06/28 20:12, , 10F
06/28 20:12, 10F
→
06/28 20:12, , 11F
06/28 20:12, 11F
→
06/28 20:14, , 12F
06/28 20:14, 12F
→
06/28 20:15, , 13F
06/28 20:15, 13F
推
06/28 20:34, , 14F
06/28 20:34, 14F
→
06/28 20:35, , 15F
06/28 20:35, 15F
→
06/28 20:36, , 16F
06/28 20:36, 16F
→
06/28 20:38, , 17F
06/28 20:38, 17F
→
06/28 20:39, , 18F
06/28 20:39, 18F
→
06/28 20:46, , 19F
06/28 20:46, 19F
→
06/28 20:47, , 20F
06/28 20:47, 20F
→
06/28 21:20, , 21F
06/28 21:20, 21F
→
06/28 21:20, , 22F
06/28 21:20, 22F
→
06/28 21:22, , 23F
06/28 21:22, 23F
推
06/28 21:29, , 24F
06/28 21:29, 24F
→
06/28 21:29, , 25F
06/28 21:29, 25F
講更詳細一點, 我喜歡的 approach (尤其適用於程式語言)
對於一個算式 我們心理想的其實是一棵樹(Abstract Syntax Tree, AST),
為了寫作方便, 寫成平的算式, 並用括弧和 operator precedence, grammar 等等
來建立一個平的字串跟這棵樹之間的關係.
+ λ
/ \ / \
1 * x @
/ \ / \
2 3 x x
1 + 2 * 3 λx. x x
而對於這棵樹有什麼 "意義", 是由我們定義決定的. 最簡單的方式是定義一個解釋函數
value_t eval(tree_t expr) {
if (expr == "+") {
return intval( eval(expr.left).intval() + eval(expr.right).intval() );
} else if (expression == "*") {
...
}
}
而當然 eval 函數會適當的決定求值順序以及好好的解釋副作用等等, 例如
...
if (expr == "?:") {
val ret = eval(expr.first);
if (res.boolval() == true)
return eval(expr.second);
else
return eval(expr.third);
} else if (expr == "&&") {
val ret = expr(expr.left);
if (ret.boolval() == true)
return eval(expr.right);
else
return false;
}
...
等等. 我們去看一般語言的定義時, 通常語意都是遞歸的定義在這棵語法樹上,
很少有直接對平平的算式做討論. 當然, 考慮普通的四則運算加減乘除, 由於
+-*/ 這幾個運算子都是 strict, 要說這導致了 +-*/ 的優先權決定了運算順序,
當然不能說是錯的. 但這畢竟是難以一般化的特例. 舉例來說, 函數呼叫其實也
可以是個 operator (我不是說 operator() ), 但函數呼叫要不要把參數先算完
是可以有不同的選擇.
回到 C++. 目前的 C++ 描述的方式是設計 value computation 跟 side effect
兩種. value computation 描述一個值的計算, 而 side effect, 副作用, 一般來說
就是做一些其他的事情像變數修改, 做 I/O 等等.
對於運算子及函數呼叫, C++ 規定了一套該運算子本身的運算和它的參數們之間
value computation, side effect 的偏序關係. 有受到偏序關係規範的我們能說
他們之間誰會先做誰會後做, 未受偏序關係規範的則還有分有可能交替著做, 或者
只能是誰先誰後(不能重疊)等等.
最簡單的例子來說, + 就規定其左右運算元的 value computation 要在 + 的
value computation 之前作完, 不過對於 side effects 則沒有規範. 當兩個
未受偏序關係規制的 side effects 影響到同一個物件時, 就是未定義行為.
回到最一開始的例子, 一個算式如 f1(g()) + f2(h(z(), w())) * f3() 當中,
其實我們副作用發生的順序根本是很寬鬆的定義的. 我們只知道 z,w 的副作用
發生在 h 之前, h 的副作用發生在 f2 之前, g 的副作用發生在 f1 之前,
其餘副作用是有可能任意穿插發生的. 在這種例子中我們很難說優先權就決定了
運算順序. 在副作用之外, 甚至在運算式 e1 + e2 + e3 當中, 三個運算元的
計算順序根本沒有確定規則. 這個算式依據優先權及結合性被解讀為
+
/ \
+ e3
/ \
e1 e2
所以我們知道 e3 跟 (e1+e2) 兩者的 value computation 要在最上面的 + 之前算完,
以及 e1 和 e2 的 value computation 要在 e1+e2 的 + 之前算完. 但是 e1, e2, e3
誰先算呢? 不知道.
此外我推文提到的 && || ?: 就是想要反駁說, expr1 && expr2 當中 && 的優先權
即使比 expr1, expr2 算式中的低, 但是 expr2 甚至根本不一定會計算到. 假使
expr1 為 false, (&&) 就計算為 false 了, 那計算順序不就比 expr2 更前面了?
同樣的 expr1 ? expr2 : expr3 這樣的 conditional, expr2 跟 expr3 也一定至
少有一個不會被算, 但 ? : 的結果還是會比不會算的那個先算出來.
※ 編輯: suhorng (36.225.42.192), 07/01/2015 01:21:08
推
07/01 01:35, , 26F
07/01 01:35, 26F
推
07/01 22:04, , 27F
07/01 22:04, 27F
→
07/01 22:04, , 28F
07/01 22:04, 28F
→
07/01 22:09, , 29F
07/01 22:09, 29F
因為語言是定義在 AST 上面的, 我會覺得, 既然 precedence 那些影響 parsing,
parsing 出來不同的 AST 又由定義有不同的結果, 當然要說 precedence 在 C++ 中
決定部份東西的先後順序是沒有問題...
不過真的只是部份順序喔. 像我舉的 e1 + e2 + e3 例子即使改成 e1 + e2 * e3,
仍然沒有說 e1, e2, e3 的 side-effects 甚至 value computation 誰先做誰後做.
我們是不知道的.
倒是有興趣的話, Haskell 是 non-strict 的, 通常都用 lazy evaluation 實現,
特點是一個東西真的被需要時才會被求值~ 例如
fib = 1 : 1 : zipWith (+) fib (tail fib)
當我們在 main 裡面 print (take 5 fib) 的時候, 會一個一個從頭開始去找 fib
的內容, 用到的才會去展開算出來, 這裡執行順序就更多的像是執行時才決定了.
※ 編輯: suhorng (36.225.42.192), 07/01/2015 23:01:08
※ 編輯: suhorng (36.225.42.192), 07/01/2015 23:01:43
推
07/01 23:49, , 30F
07/01 23:49, 30F
→
07/01 23:49, , 31F
07/01 23:49, 31F
→
07/01 23:49, , 32F
07/01 23:49, 32F
→
07/01 23:50, , 33F
07/01 23:50, 33F
→
07/01 23:50, , 34F
07/01 23:50, 34F
推
07/02 00:03, , 35F
07/02 00:03, 35F
→
07/02 00:06, , 36F
07/02 00:06, 36F
→
07/02 00:14, , 37F
07/02 00:14, 37F
→
07/02 00:17, , 38F
07/02 00:17, 38F
→
07/02 00:48, , 39F
07/02 00:48, 39F
→
07/02 00:48, , 40F
07/02 00:48, 40F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 4 篇):
C_and_CPP 近期熱門文章
PTT數位生活區 即時熱門文章