C語言向屏幕上寫數據的最簡單和最快的方法是什麼?

向屏幕上寫數據的最簡單的方法是什麼?

C語言包含了大約幾百個向屏幕上寫數據的函數,很難決定在某一時刻最適合用哪一個函數來向屏幕上寫數據。許多程序員只是簡單地選擇一個或兩個打印函數,並且以後只使用這些函數。這是一種可以接受的編程風格,儘管這樣的程序員也許不是總能寫出最好的代碼。

一個程序員應該做的就是把每個打印函數的設計目的和最佳用法都回顧一遍,這樣,當他需要向屏幕上打印數據時,他就能選出最佳的函數,甚至還可以自己編寫一些打印函數。

要成爲一個真正熟練的程序員,第一步要做的工作的一部分就是學會正確地使用標準C語言庫中的打印函數。讓我們仔細地分析一下其中的幾個函數。
    printf(<format string>,variables);
printf()是使用最廣泛的打印函數。在把文本輸出到屏幕上時,有些程序員只使用這個函數。儘管如此,該函數的設計目的只是用來把帶格式的文本打印到屏幕上。實際上,“printf"是“print formatted(帶格式打印)”的縮寫。帶格式的文本是指文本中不僅僅包含寫到代碼中的字符串,還包含由程序動態生成的數字、字符和其它數據;此外,它的內容可以按一種特定的方式顯示,例如,它可以按所指定的小數點前後的位數來顯示實數。正是由於這個原因,所以printf()函數是不可缺少的!

那麼,爲什麼有時又不使用printf()呢?這裏有幾個原因。
第一個原因是程序員想更清楚地表達他的意圖。程序員可能只對printf()函數提供的諸多功能中的一小部分感興趣,在這種情況下,他可能想使用只提供這一小部分功能的那個函數,例如:
    putchar(char);
該函數的作用是把一個字符送到屏幕上。如果你只需做這部分工作,那麼它是十分合適的。除此之外,它就不見得有什麼好處了。然而,通過使用這個函數,你就能非常清楚地表達相應的那部分代碼的意圖,即把單個字符送到屏幕上。
    puts(char*);
該函數的作用是把一個字符串寫到屏幕上。它不能象printf()一樣接受額外的數據,也不能對傳遞過來的字符串加以處理。同樣,通過使用這個函數,你就能非常清楚地表達相應的那部分代碼的意圖。

程序員不使用printf()的第二個原因是爲了提高程序的執行效率。printf()函數的額外開銷太多,也就是說,即使是進行一次簡單的操作,它也需要做大量的工作。它需要檢查傳遞過來的字符串與格式說明符是否匹配,還需要檢查傳遞過來的參數個數,等等。上面提到過的另外兩個函數沒有這些額外的開銷,因此它們可以執行得非常快。這個因素對大多數向屏幕上寫數據的程序來說並不重要,但是,在處理磁盤文件中的大量數據時,它就顯得很重要了。

不使用printf()的第三個原因是程序員想減小可執行程序的大小。當你在程序中使用了標準C函數時,它們必須被“連接進來”,也就是說,它們必須被包含進所生成的可執行文件中。對於象putchar()和puts()這樣簡單的打印函數,對應的程序段是很短的,而對應於printf()的程序段卻相當長——特別是因爲它必然要包含前兩個函數。

第二個原因可能是最不重要的一個原因,然而,如果你在使用靜態連接程序,並且想保持較小的可執行文件的話,那麼這就是一項重要的技巧了。例如,儘可能減小TSR和其它一些程序的大小是很值得的。

無論如何,程序員都應根據自己的目的來選擇需要使用的函數。

向屏幕上寫文本的最快的方法是什麼?

通常,你不會過分關心程序寫屏幕的速度。但是,在有些應用中,需要儘可能快地寫屏幕,這樣的程序可能包括:
  1. 文本編輯器。如果不能很快地寫屏幕,則由用戶輸入文本所造成的屏幕滾動和其它有關操作可能會顯得太慢。
  2. 活動的文本。在同一區域快速地打印字符,是獲得動畫效果的一種常用手段,如果不能快速地把文本打印到屏幕上,那麼動畫就太慢了,視覺效果就不會好。
  3. 監視器程序。這樣的程序要連續地監視系統、其它程序或硬件設備,它可能需要每秒在屏幕上打印多次狀態的更新信息,而通過標準c庫函數實現的屏幕打印對這樣的程序來說很可能顯得太慢。

那麼,在這些情況下應該怎麼辦呢?有三種辦法可以加快程序寫屏幕的速度:選用額外開銷較小的打印函數;使用提供了快速打印功能的軟件包或函數庫;跳過操作系統,直接寫屏幕。下面將按從簡到繁的順序分析這幾種辦法。
1、選用額外開銷較小的打印函數
有些打印函數的額外開銷比別的打印函數要多。“額外開銷”是指與其它函數相比,某個函數必須做的額外工作。例如,printf()的額外開銷就比puts()多。那麼,爲什麼會這樣呢?

puts()函數是很簡單的,它接受一個字符串並把它寫到顯示器屏幕上。當然,printf()函數也能做同樣的工作,但它還要做大量其它的工作——它要分析送給它的字符串,以找出指示如何打印內部數據的那部分特殊代碼。

也許你的程序中沒有特殊字符,而且你也沒有傳遞任何這樣的字符,但不幸的是,printf()無法知道這一點,它每次都必須檢查字符串中是否有特殊字符。

函數putch()和puts()之間也有一點微小的差別——在只打印單個字符時,putch()的效果更好(額外開銷更少)。

遺憾的是,與真正把字符寫到屏幕上所帶來的額外開銷相比,這些C函數本身的額外開銷是微不足道的。因此,除了在一些特殊情況下之外,這種辦法對程序員不會有太大的幫助。

2、使用提供了快速打印功能的軟件包或函數庫
這可能是有效地提高寫屏速度的最簡單的辦法。你可以得到這樣的一個軟件包,它或者會用更快的版本替換編譯程序中固有的打印函數,或者會提供一些更快的打印函數。

這種辦法使程序員的工作變得十分輕鬆,因爲他幾乎不需要改動自己的程序,並且可以使用別人花了大量時間優化好了的代碼。這種辦法的缺點是這些代碼可能屬於另一個程序員,在你的程序中使用它們的費用可能是昂貴的。此外,你可能無法把你的程序移植到另一種平臺上,因爲那種平臺上可能沒有相應的軟件包。

不管怎樣,對程序員來說,這是一種既實用又有效的辦法。

3、跳過操作系統,直接寫屏幕   
由於多種原因,這種辦法有時不太令人滿意。事實上,這種辦法在有些計算機和操作系統上根本無法實現。此外,這種辦法的具體實現通常會因計算機的不同而不同,甚至在同一臺計算機上還會因編譯程序的不同而不同。

不管怎樣,爲了提高視頻輸出速度,直接寫屏是非常必要的。對全屏幕文本來說,你可能可以每秒種寫幾百屏。如果你需要這樣的性能(可能是爲了視頻遊戲),採用這種辦法是值得的。

因爲每種計算機和操作系統對這個問題的處理方法是不同的,所以要寫出適用於所有操作系統的程序是不現實的。下文將介紹如何用Borland c在MS-DOS下實現這種辦法。即使你不使用這些系統,你也應該能從下文中瞭解到正確的方法,這樣你就可以在你的計算機和操作系統上寫出類似的程序了。

首先,你需要某種能把數據寫到屏幕上的方法。你可以創建一個指向視頻緩衝區的指針。在MS-DOS下使用Borland C時,可以用下述語句實現這一點:
    char far*Sereen=MK_FP(0xb800,Ox0000);
far指針所指向的地址並不侷限於程序的數據段中,它可以指向內存中的任何地方。MK_FP()產生一個指向指定位置的far指針。有些其它的編譯程序和計算機並不要求區分指針的類型,或者沒有類似的函數,你應該在編譯程序手冊中查找相應的信息。

現在,你有了一個“指向”屏幕左上角的指針。只要你向該指針所指向的內存位置寫入若干字節,相應的字符就會從屏幕的左上角開始顯示。下面這個程序就是這樣做的:
    #include<dos.h>
    main()
    {
       int a:
       char far*Screen=MK_FP(Oxb800。Ox0000):
       for(a=0;a<26;++a)
       sereen[a*2]='a'+a:
       return(O);
    }
該程序運行後,屏幕頂端就會打印出小寫的字母表。

你將會發現,字符在視頻緩衝區中並不是連續存放的,而是每隔一個字節存放一個。這是爲什麼呢?這是因爲一個字符雖然僅佔一個字節,但緊接着它的下一個字節要用來存放該字符的顏色值。因此,屏幕上顯示的每個字符在計算機內存中都佔兩個字節:一個字節存放字符本身,另一個字節存放它的顏色值。

這說明了兩點:首先,必須把字符寫入內存中相隔的字節中,否則你將會只看到相隔的字符,並且帶有古怪的顏色。其次,如果要寫帶顏色的文本,或者改變某個位置原有的顏色,你就需要自己去寫相應的顏色字節。如果不這樣做,文本仍然會按原來的顏色顯示。每個描述顏色的字節既要描述字符的顏色(即前景色),又要描述字符的背景色。一共有16種前景色和16種背景色,分別用顏色字節的低4位和高4位來表示。   

這部分內容對一些缺乏經驗的程序員來說可能有點複雜,但還是比較容易理解的。只要記住有16種顏色,其編號範圍是從。到15,要得到顏色字節的值,只需把前景色的值和背景色值的16倍相加即可。下面這個程序就是這樣做的:
    #include<stdio.h>
    main()
    {
       int fc,bc,c;
       scanf("%d %d",&fc,&bc);
       printf("Foreground=%d,Background=%d,Color=%d\n",
       fc,bc,fc+bc*16);
       return(0);
    }
你可能會同意這樣一點,即在大多數情況下,在整個程序中都由程序員明確地寫出要送到屏幕上的字節是不現實的。最好是編寫一個把文本寫到屏幕上的函數,然後頻繁地調用這個函數。讓我們來分析一下如何構造這樣一個函數。

首先,你需要問一下自己:“我需要向這個通用打印函數傳遞一些什麼信息?”作爲初學者,你可以傳遞以下這些信息:
  1. 要寫到屏幕上的文本;
  2. 文本的位置(兩個座標值)
  3. 字符的前景色和背景色(兩個值)

現在,你知道了需要把什麼數據傳遞給該函數,因此你可以按以下方式來說明這個函數:
    void PrintAt(char*Text,int x,int y,int bc,intfc)
下一步你需要計算要打印的文本的顏色字節值:
    int Color=fc+be*16:
然後需要計算文本指針的起始位置:
    char far*Addr=&screen[(x+y*80)*2];
需要特別注意的是,爲了把文本寫到正確的位置上,你必須把偏移量乘以2。此外,使用該語句的前提是在程序中已經定義了變量Screen。如果該變量還未定義,你只需在程序中相應的位置插入下述語句:
    char far*Screen=MK_FP(0xb800,0x0000);
現在,準備工作都完成了,你可以真正開始向屏幕上寫文本了。以下是完成這項任務的程序段:
    while(*Text)
    {
       *(Addr++)=*(Text++);
       *(Addr++)=Color;
    }
在還未寫完全部文本之前,這段代碼會一直循環下去,並把每個字符和對應的顏色寫到屏幕上。

以下這個程序中給出了這個函數完整的代碼,並且調用了一次該函數。
    #include(dos.h>
    /*This is needed for the MK—FP function*/
    char far*Screen=MK_FP(Oxb800,Ox0000):
    void PrintAt(char*Text,int x,int y,int bc,int fc)
    {
       int Color=fc+bc*16;
       char far*Addr=&screen[(x+y*80)*2];
       while(*Text)
       {
          *(Addr++)=*(Text++);
          *(Addr++)=Color;
       }
    }
    main()
    {
       int a:
       for(a=1;a<16:++a)
       PrintAt("This is a test",a,a,a+1,a);
       return(0);
    }
如果比較一下這個函數和固有的打印函數的執行時間,你會發現這個函數要快得多。如果你在使用其它硬件平臺,你可以用這裏所提供的思路來爲你的計算機和操作系統編寫一個類似的快速打印函數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章