Try   HackMD

2018q1 Homework2 (assesment)

contributed by <team6612> (Daniel Chen)

第一週測驗 Q3

在 C 程式中,表達式 1 << 2 + 3 << 4 求值後為何?
(a) 512
(b) 16
(c) 26
(d) 52
(e) 25

延伸問題:

  • 在 C 語言規格書中,找出對應運算子優先權的描述並嘗試解讀

思考

在 C11 (ISO/IEC 9899:2011) 規格書中,有關運算子的優先順序定義在 6.5 Expressions 一章中,一連串的運算元和運算子組合起來稱爲 Expression,可用來表達:求值、指派、產生 side effect、或以上的組合。

在規格書中定義優先順序的方式不是列出個列表標示每個運算子的順序,而是一連串的語法定義,來告訴編譯器實作應該要先處理哪種運算子,一共分成 17 種 Expressions,分別是:

  1. Primary expressions
  2. Postfix operators
  3. Unary operators
  4. Cast operators
  5. Multiplicative operators
  6. Additive operators
  7. Bitwise shift operators
  8. Relational operators
  9. Equality operators
  10. Bitwise AND operator
  11. Bitwise exclusive OR operator
  12. Bitwise inclusive OR operator
  13. Logical AND operator
  14. Logical OR operator
  15. Conditional operator
  16. Assignment operators
  17. Comma operator

各 Expression 的定義可能由別種 Expression 所表達,表示別種 Expression 必須先組合起來再解讀該 Expression,例如 unary-expression 的定義

unary-expression:
    postfix-expression
    ++ unary-expression
    -- unary-expression
    unary-operator cast-expression
    sizeof unary-expression
    sizeof ( type-name )
    _Alignof ( type-name )
    
unary-operator: one of
    & * + - ~ !

中包含 postfix-expressioncast-expression,意味着當 Expression 中包含這兩種 Expression 時必須先解讀postfix-expression & cast-expression 再解讀 unary-expression

C Operator Precedence - cppreference.com 將這樣的關係整理成 precedence table,但也有提到不是所有的語法定義都可以很好的用次序表定義,例如三元運算子。

相關議題

有關 side-effect 的順序

6.5 中第二點提到

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

並舉了兩個例子

a[i++] = i;  //! undefined
a[i] = i;    //  allowed
i = ++i + 1; //! undefined
i = i + 1;   //  allowed

第一次看的時候不太懂,於是去找了一些資料來看,其中在 StackOverflow 上找到的這篇這篇有討論到這個規範的解讀,目前還在研究當中。

string-literal

string-literalprimary-expression 的一種,用來表示字串,規格書在敘述中有提到 string-literallvalue,宣告時就佔有記憶體空間,可以對其做相關操作,之前並無注意到此特性,因此做了一點小實驗,對 string-literal 進行 address-of (&) 操作:

printf("&\"string-literal\" = %p\n", &"string-literal");

執行結果

&"string-literal" = 0x561204b247de

Reference

ISO/IEC 9899:2011 - WG14 draft version N1570