看板 Gossiping作者 grapherd (NULL)標題 Re: [問卦] C語言沒人用goto?時間 Thu Oct 12 06:56:41 2017
※ 引述《bencert (根本ㄏㄏ)》之銘言:
: 小弟我剛剛想起來
: C語言有種用法是goto
: 但是上程式設計的課老師也跳過不教
: 我看也沒人用過goto
: 有沒有C語言GOTO的八卦?
: -----
: Sent from JPTT on my Samsung SM-G930F.
八卦是,ptt 的程式碼裡面也有使用 goto.
在 c99 spec 裡面,goto 是定義在 6.8.6 Jump Statements
其中的 6.8.6.1 The goto statement. 作用就是提供一個無條件
跳躍的功能. Spec 裡面給的範例是這個:
/* ... */
goto first_time;
for (;;) {
// determine next operation
/* ... */
if (need to reinitialize) {
// reinitialize-only code
/* ... */
first_time:
// general initialization code
continue;
}
// handle other operations
/* ... */
}
基本上這樣的形式,還是能夠做簡化的,只要把 first_time label
下面的 initialization code 做成一個 function 去 call,就不用
用到 goto label 了。
至於會使用到 goto 的一些理由,在要求結構化程式碼,以及編譯器
優化隨著技術進步的關係,也越來越站不住腳了。
至於為什麼台灣都有種無腦不使用 goto 的教條呢?因為當老師的
只會舉一些鳥蛋的例子啊:
int main() {
int i = 0;
loop:
printf("%d\n", i++);
if (i < 10)
goto loop;
}
然後就沒了。
然後就沒了。
然後就沒了。
目前比較大的 C 語言專案中用到 goto,幾乎都是在做 exception handling 的部分,
因為 C 語言的特性,出錯了的時候,很多動態配置的記憶體會需要回收掉,
要不然會造成 memory leak。這時候 goto 就變得很方便。例如說 CPython
的這段程式碼:
static void
TaskObj_finalize(TaskObj *task)
{
/* ... */
if (task->task_state != STATE_PENDING ||
!task->task_log_destroy_pending) {
goto done;
}
/* ... */
context = PyDict_New();
if (context == NULL) {
goto finally;
}
message = PyUnicode_FromString("Task was destroyed...");
if (message == NULL) {
goto finally;
}
/* ... */
finally:
Py_XDECREF(context);
Py_XDECREF(message);
/* Restore the saved exception. */
PyErr_Restore(error_type, error_value, error_traceback);
done:
FutureObj_finalize((FutureObj*)task);
}
https://github.com/python/cpython/blob/master/Modules/_asynciomodule.c#L1711
這邊就能很明顯看出 goto 的作用啦,第一個
goto done
,因為還沒有
allocate context 或是 message,所以不需要去做善後的工作,如果這時候
觸發這個 goto 的話,就直接到底就好。
但是如果遇到 context 或是 message allocate 失敗的話,因為已經有
allocate 一些資源,就必須要跳到 finally 去把這些資源給清空以及還原。
在 Linux kernel 裡面也有許多需要做 exception handling 的部分,
因此也大量的使用了 goto, 但不太會有教科書上那種錯誤範例的使用方式
在裡面就是了。
最後,pttbbs 本身也有用啊 XDDD
https://github.com/ptt/pttbbs/blob/master/mbbsd/brc.c#L689
https://github.com/ptt/pttbbs/blob/master/mbbsd/brc.c#L704
https://github.com/ptt/pttbbs/blob/master/mbbsd/edit.c#L2250
https://github.com/ptt/pttbbs/blob/master/mbbsd/edit.c#L1848
https://github.com/ptt/pttbbs/search?q=goto
更多 goto,請參考 wikipedia:
https://en.wikipedia.org/wiki/Goto#Common_usage_patterns_of_Goto
Goto - Wikipedia GoTo (goto, GOTO, GO TO or other case combinations, depending on the programming language) is function call normally returns control. The jumped-to locations are usually identified using labels, though some languages use line numbers. At the machine code level, a goto is a form of branch or jump sta ...
--
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.113.63.78
※ 文章代碼(AID): #1Ptg6po0 (Gossiping)
※ 文章網址: https://www.ptt.cc/bbs/Gossiping/M.1507762611.A.C80.html
※ 編輯: grapherd (140.113.63.78), 10/12/2017 06:58:05
推 sppmg: 認真文給推1F 10/12 07:02
→ pzyc79: 語義不明 就不要怪人們亂用2F 10/12 07:02
推 PONANZA: 快推 不然人家會以為我看不懂7F 10/12 07:44
→ moonshade: 通常是用在early exit 之類的,但是因為有很多亂用的人所以教學上會先教不要用,你如果看過一些光怪陸離
C/C++ 使用方法就會覺得教不要用是對的8F 10/12 07:55
推 bab7171: linux kernel用超多11F 10/12 07:56
→ jodojeda: 我不用goto這種爛指令 我都用comefrom12F 10/12 08:05
推 louiseeg: 應該要有一本書叫 the art of goto13F 10/12 08:11
推 wanzi0601: 我認為goto解讀會變差..不太用16F 10/12 08:18
推 lpoijk: 不用goto是哪些人...?18F 10/12 08:37
推 OGC218: 文組如我…看不懂22F 10/12 08:48
推 greed3819: 我們老師跟我說這樣會破壞程式結構叫我們不要使用,就連課本裡也寫不建議使用?23F 10/12 08:52
推 xhung: 推 認真文 goto在err_handling真的方便XD25F 10/12 09:04
推 a2470abc: 優文推 goto實務好像都拿來做例外的處理26F 10/12 09:14
→ mikapauli: 因為例外處理本身就是一件破壞程式結構的事情27F 10/12 09:19
推 loloman: 就科技廠的機台可以處理run time error hang up狀況28F 10/12 09:20
推 musie: 沒有delimited continuation的低階語言才會要用goto32F 10/12 09:51
→ buffalobill: 動態配製那邊通常會用do{}while(0);加上break;吧33F 10/12 09:52
推 dou0228: 不是,通常是最後要回收 memory 或其他 resource
goo.gl/p3v23T34F 10/12 09:54
推 aadsl: 完全看不懂 哀 難怪我只能領低薪40F 10/12 11:30
推 kersihi: 完全看不懂 哀 難怪我只能領低薪42F 10/12 12:22
推 AirLee: 樓上我也是43F 10/12 13:06
推 greg870601: 沒辦法R C++比較強,goto基本上沒用了45F 10/12 13:34
推 dou0228: C++ 能比 goto 難懂的東西多得是46F 10/12 14:30
推 vvrr: 用do{}while(0)+break,跳出do之後還是要跑過接下來的每一行goto可以根據不同的錯誤,跳過某些行。當然也可以在break
前設好錯誤碼,再根據錯誤碼寫if/else,但這樣反而很亂..47F 10/12 15:39
--