printf的實現
printf的聲明
int _cdecl printf(const char* format, …);
_cdecl是C和C++程序的缺省調用方式
_CDEDL調用約定:
1.參數從右到左依次入棧
2.調用者負責清理堆棧
3.參數的數量類型不會導致編譯階段的錯誤
對於x86而言,棧向下生長,函數參數從右向左入棧,因此從第一個固定參數(format)地址向前(向上)移動就可得到其他變參的地址。
va_list相關宏(VC++中stdarg.h裏x86平臺的宏定義)
typedef char * va_list;
//_INTSIZEOF(n)宏:將sizeof(n)按sizeof(int)對齊。
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
//取format參數之後的第一個變參地址,4字節對齊
#define va_start(va_list ap, format) ( ap = (va_list)&format+ _INTSIZEOF(format) )
//對type類型數據,先取到其四字節對齊地址,再取其值
#define va_arg(va_list ap,type)
( *(type*)((ap += _INTSIZEOF(type)) -_INTSIZEOF(type)) )
#define va_end(va_list ap) ( ap = (va_list)0 )
如何得到參數個數?
其實printf並不知道參數個數,它只是逐個解析format字符串。對於特定類型%,使用va_arg去取相應參數的值,直到遍歷字符串結束。類似於如下代碼:
#include <stdio.h>
#include <stdarg.h>
void myprintf(const char *format, ...)
{
va_list ap;
char ch;
va_start(ap, format);
while(ch = *format++)
{
switch(c)
{
case 'c':
{
char ch1 = va_arg(ap, char);
putchar(ch1);
break;
}
如下調用會打印什麼內容?
printf(“%x”);
Makefile
1.什麼是Makefile
(1)一個工程中的源文件不計其數,其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的
規則來指定,哪些文件需要先編譯,哪些文件需要後編譯,哪些文件需要重新編譯,甚至於進行更復雜
的功能操作,因爲 makefile就像一個Shell腳本一樣,其中也可以執行操作系統的命令。
(2)所要完成的Makefile 文件描述了整個工程的編譯、連接等規則。其中包括:工程中的哪些源文件需要編譯
以及如何編譯、需要創建那些庫文件以及如何創建這些庫文件、如何最後產生我們想要的可執行文件。
儘管看起來可能是很複雜的事情,但是爲工程編寫Makefile 的好處是能夠使用一行命令來完成“自動化編
譯”,一旦提供一個(通常對於一個工程來說會是多個)正確的 Makefile。編譯整個工程你所要做的唯一
的一件事就是在shell 提示符下輸入make命令。整個工程完全自動編譯,極大提高了效率。
(3)make是一個命令工具,它解釋Makefile 中的指令(應該說是規則)。在Makefile文件中描述了整個工程所
有文件的編譯順序、編譯規則。Makefile 有自己的書寫格式、關鍵字、函數。像C 語言有自己的格式、關
鍵字和函數一樣。而且在Makefile 中可以使用系統shell所提供的任何命令來完成想要的工作。
Makefile(在其它的系統上可能是另外的文件名)在絕大多數的IDE 開發環境中都在使用,已經成爲一種
工程的編譯方法。