前文鏈接:http://www.cnblogs.com/pmer/archive/2013/09/17/3327262.html
A,局部變量的返回地址
Q:下面的代碼有問題嗎?如果有,如何修改?
#include<stdio.h> int* inc(int val) { int a = val; a++; return &a; } int main(void) { int a = 10; int *val = inc(a); printf("\n Incremented value is equal to [%d] \n", *val); return 0; }A:雖然上面的代碼有時運行會很好,但是在方法 inc() 中有很嚴重的隱患。當inc()方法執行后,再次使用局部變量的地址就會造成不可估量的結果。解決之道就是傳遞變量a的地址給main()。
Answer: Though the above program may run perfectly fine at times but there is a serious loophole in the function ‘inc()’. This function returns the address of a local variable. Since the life time of this local variable is that of the function ‘inc()’ so after inc() is done with its processing, using the address of its local variable can cause undesired results. This can be avoided by passing the address of variable ‘a’ from main() and then inside changes can be made to the value kept at this address.
評:
這個主要是翻譯的問題。對照一下原文就會發現,譯文不但漏掉了很多內容沒有翻譯,最嚴重的是把“by passing the address of variable ‘a’ from main()”給翻譯成了“傳遞變量a的地址給main()”,徹底顛覆了原文的意思。原意是傳遞main()中變量a的地址,即調用形式為int(&a),而譯文的意思依然是代碼中那種錯誤寫法的描述。
B,處理 printf() 參數
Q:以下代碼輸出請問是什么?
#include<stdio.h> int main(void) { int a = 10, b = 20, c = 30; printf("\n %d..%d..%d \n", a+b+c, (b = b*2), (c = c*2)); return 0; }A:輸出將是
1 110..40..60
這是因為參數都是從右向左處理的,然后打印出來卻是從左向右。
Answer: The output of the above code would be :
110..40..60
This is because the arguments to the function are processed from right to left but are printed from left to right.
評:
這個問題和解答都很狗血!
“參數都是從右向左處理的”是無中生有。C標准規定
The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
也就是說實參的求值次序沒做規定(unspecified),編譯器可以自己安排計算次序,無論怎樣安排都不違背標准。從右向左或從右到左都可以。斷言“參數都是從右向左處理”,是這個解答中第一個錯誤。
前面引用條文中還提到了在實際調用前存在一個序點(sequence point),對於代碼中
printf("\n %d..%d..%d \n", a+b+c, (b = b*2), (c = c*2))
這個函數調用來說,前一個序點就是之前的“;”。
C語言的另一個規定是:
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.Furthermore, the prior value shall be read only to determine the value to be stored.
這兩句話是什么意思呢?前一句說的是兩個相鄰序點之間,一個數據對象的值最多可以改變一次。如果改變多次,就是未定義行為。譬如寫出下面代碼
printf("%d,%d,%d,%d\n", ++i, --i, i++, i--);
就是出於典型的對未定義行為的無知。而津津樂道、煞有介事地討論這種根本沒有意義的代碼(i++和++i作為參數時的編譯器處理方式分析~) ,就如同譚浩強津津樂道地討論a+=a-=a*a一樣荒唐(參見“牙里長嘴”和“a+=a-=a*a” ),我擦,豈不是滑天下之大稽?只有根本沒有技術能力又缺乏自知之明的怨婦,才可能無聊到做這種荒謬無價值的事情。
標准條文中的后面一句有些晦澀,它的意思是數據對象中先前的值只能是用來確定數據對象中后來存儲的值,例如:
int i = 1; i = i + 1 ;
i只改變了一次,且i的原值(1)用來確定i后來存儲的值(2)。
如果數據對象的值在兩個序點之間只改變一次,且數據對象的原值不是用來確定數據對象后來的值,例如:
int i = 1 , j ; j = i + (i = 2) ;
則屬於未定義行為。因為表達式中第一個i的值不是為了確定i將要存儲的值。沒人說的清這個i + (i = 2) 這個表達式的值應該是4還是3。
回過頭再看問答代碼中的
printf("\n %d..%d..%d \n", a+b+c, (b = b*2), (c = c*2));
b和c都被改變一次,但由於在表達式a+b+c中,b和c的值不是用來確定b和c最終的值,因此這段代碼屬於沒有意義的未定義行為。
因此,這個問答一共錯了兩處。一處是說“參數都是從右向左處理的”,另一處就是代碼行為未定義。
(全文完)