顯示具有 程式語言 標籤的文章。 顯示所有文章
顯示具有 程式語言 標籤的文章。 顯示所有文章

2010年6月16日

GDB中如何存取不在current context的static variable

下午和 型男hasashi 討論一個malloc/free的問題,他寫了一個小程式來驗證malloc是否會自動free這件事,但是會 segmentation fault,我就想說開GDB來debug,同時練習GDB的用法。(自從上次在元智大學聽 變態 高手 Jserv 講解過GDB就一直在找機會練習 :D)

雖然說事後想一想這小程式其實意義不大,所以這程式邏輯是什麼也就不是重點了XD 但是碰到一個很有趣的GDB問題,所以想筆記一下。

這程式中,main會call一個function,裡面建立一個 static variable叫xxx,我想監看這個變數,不過如果程式離開這個function回到main了,我們在gdb裡要p(print)這個變數會出現:

No symbol "xxx" in current context.

所以我知道這個static variable其實存在,但是我看不到。雖然發現用把xxx加到display卻可以印出,我也不知道為什麼?(補充一下display的作用:每次breakpoint被觸發的時候,有被加到display裡的參數會自動被gdb print出來,就不用手動print。) 而且,只有display並不夠,因為有時會想存取這個變數來複製、assign給別的變數或做別的動作。

於是我先去 stackoverflow 找,但並沒有找到相關討論;接著我去google "gdb static variable No symbol  in current context",發現答案就在 gdb manual 裡;在 "Examining Data" 這一章的 "Program Variables" 這一節提到:

...If you wish, you can specify a static variable in a particular function or file, using the colon-colon (::) notation:
file::variable
function::variable
Here file or function is the name of the context for the static variable....

所以就可以很快樂的用 function::xxx 這種方式來存取不在current context的static variable了!

ps. 也許這就是沒先k過manual的報應啊…可是 gdb manual 有整整 32 章耶(不含一堆附錄)!?而且又不是只有gdb要看,想看的文件太多了,要怎麼取得平衡對我來說還是一個未解的問題…。

ps2. 在使用"gdb --tui"時曾經碰到好幾次上方視窗的source code會突然亂掉,發現別人也有碰過這個問題,但是暫時不知道解法,也許要找一個好的front-end來用。


2009年11月25日

printf() 與 fflush()

flush-t15018

有時候在用printf(),例如debug,會發現前面一句printf()的輸出反而會比後面一句printf()的輸出還慢,例如:

printf("111");
printf("222");
有時會先印出222

這種情況會造成很多的不確定性和debug困擾。

但如果在 printf() 後面加上 fflush(stdout); 就解決了。(這是在C,和C++的 flush 不太相同)

也就是改成以下就沒問題:

printf("111");
fflush(stdout);
printf("222");
fflush(stdout);

因為 fflush() 能把 stdout 這個 stream 的 buffer 強制沖(flush)出,也就是先寫出再說(write)。

講的可能不是很清楚,有興趣的話可以man fflush,或是google 「printf fflush」。

以下是我自己的摘錄:

NAME
fflush - flush a stream

SYNOPSIS
#include <stdio.h>
int fflush(FILE *stream);

DESCRIPTION
The function fflush() forces a write of all user-space buffered data for the given output or update stream via the stream's underlying write function. The open status of the stream is unaffected.
If the stream argument is NULL, fflush() flushes all open output streams.

NOTES
Note that fflush() only flushes the user space buffers provided by the C library. To ensure that the data is physically stored on disk the kernel buffers must be flushed too, for example, with sync(2) or fsync(2).

順帶一提,google時有看到另一個不太一樣的問題,有人會用fflush(stdin) 來刷新scanf,這是沒定義的行為,不能亂用。

2008年12月1日

Array initialization (陣列初始化) in C

UPDATE: 2010-06-18

最近在PTT的C_and_CPP版上問了一些關於C的array initialization問題,討論之後的整理筆記如下(以下用 gcc 4.3.4 + gdb 7.0 測試)

(1) array沒初始:初始值是垃圾值

int num[10];
或
char array[10];

(2a) array部份初始版本1(不是用大括弧):除了有被初始的以外,都是垃圾值

int num[10];
num[0] = 999; //num[0]以外都是垃圾值
或
char array[10];
array[0]='a'; //array[0]以外都是垃圾值

(2b) array部份初始版本2(用大括弧):沒初始的部份會自動補成0

int num[10] = {1,2,3};
或
int num[10] ={};

ps. char array[10] = ""; //也會自動補0,我猜是因為這相當於char array[10] = {'\0'};

會自動補0的原因如下:

(節錄自tinlans大,英文是C99的一段)
[...If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
array 和 struct 這類東西在程式語言裡都被歸類為 aggregate (聚合資料)...]

粗略的總結就是:

如果aggregate型別(如array/struct)初始不完全,而且又是用大括弧方式初始,compiler就會像對static變數一樣,自動把沒初始到的補0

所以,我們可以用以下初始方式把array初值都設為0:

int num[10] = {0};

但是要觀念上要清楚,不要誤解成所有元素都會設成同樣的值,以下就是可能的誤用:

int num[10] = {255}; //這樣其實只有第一個是255,其他元素是會自動補0,不是全部都設成255。

以上如果有錯,請留下您的意見一起討論!