RT,看到書上有個判斷語句是if(pre->next != NULL pre->next->data != 0) 就比較好奇若是此時pre->next已經是空指針了,對後面pre->next的data域的訪問不就是非法的了么。恰好身邊沒電腦可以驗證我的想法,不知有無大神能解我的疑惑,不勝感激


不會:如果第一個操作數與 0 相等,不會對第二個操作數進行求值。

The operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

If the first operand compares equal to 0, the second operand is not evaluated.

C89 §3.3.13 · C99 §6.5.13/4 · C11 §6.5.13/4 · Logical operators

p.s. 因為 C 語言有未定義行為的概念,所以通過實驗驗證想法有可能得出片面甚至錯誤的結論,正確的做法是查文檔。

p.p.s. C++ 同理,除了定義里用的不是 0 和 1 而是 false 和 true 之外基本是一樣的。


不會。這是短路計算。

類似的,if (A || B) 如果A表達式的結果是真,那麼就不會計算B表達式了。

嚴格講,C語言沒有真值和假值,邏輯判斷把非0看成真,0看成假。


額~這應該是一道C語言的必考題,我參加過的所有編碼考試中都有這道題。

就是不用。一個條件滿足的就不會去執行後面的判斷了


你的 C 語言教材難道不講這個知識點?


B不管真假,結果已經註定是假,繼續求值沒什麼意義


不用多想,看看下面這個c函數編譯出來的彙編文件是怎麼樣就可以了:

int f(int a, int b)
{
if (a b) {
return 1;
} else {
return 0;
}
}

編譯:

unix&> gcc -S test.c -o test.s

生成的彙編文件如下:

.file "test.c"
.option nopic
.text
.align 2
.globl f
.type f, @function
f:
addi sp,sp,-32
sw s0,28(sp)
addi s0,sp,32
sw a0,-20(s0)
sw a1,-24(s0)
lw a5,-20(s0)
beqz a5,.L2
lw a5,-24(s0)
beqz a5,.L2
li a5,1
j .L3
.L2:
li a5,0
.L3:
mv a0,a5
lw s0,28(sp)
addi sp,sp,32
jr ra
.size f, .-f
.ident "GCC: (GNU) 8.2.0"

riscv32體系結構調用協定中,用寄存器a0至a7傳遞參數,用寄存器a0或{a1, a0}傳遞返回值。

f中的兩條sw指令將a0和a1存入堆棧,也就是局部變數a和b;

然後先取局部變數a的值存入寄存器a5,並判斷a5是否為假,如果為假就跳轉到.L2(不再判斷局部變數b)。否則,繼續取局部變數b的值存入寄存器a5,再判斷是否為假,如果為假仍然跳轉到.L2。否則,利用a5暫存返回值1,並跳轉到.L3;

.L2利用a5暫存返回值0,並執行.L3;

.L3將暫存返回值寄存器a5的值存入返回值寄存器a0,釋放當前棧幀並返回。

c語言的種種規則只是一份標準文件,背誦標準文件不如看看被固化為程序的標準文件(編譯器)對輸入的行為。


通常編譯器是不知道運行時變數的值的,所以兩邊的表達式都會被編譯成二進位。但是如果編譯時可以肯定左邊是偽,那麼大多數編譯器會直接報警,或者直接把右邊和整個語句塊優化沒了。

另外我覺得萬一你想說的應該不是編譯器而是運行時,那隻能對你說:Read the Fucking Book

不會,且的意思前邊已經為假了後邊就不會再執行了!


計算與否是C語言標準規定的么?假如後面的算式改變某個變數的值,不同的實現會導致程序結果不一致的吧。


不會,這是短路問題。外:可以考慮更換你的C教材,如c primer plus


百度

| 和||

8和88(手機沒找到它)

區別


這種事是編譯器乾的,所謂優化就是類似的東西,只是你說的這種,是連初學者都會考慮的優化,那寫編譯器的大神,怎麼會考慮不到?


推薦閱讀:
查看原文 >>
相关文章