English Deutsch Français Italiano Español Português 繁體中文 Bahasa Indonesia Tiếng Việt ภาษาไทย
所有分類

寫程式也好一段時間了,老實說一直有個疑問,一般而言函數宣告時,固定數量的參數傳入的函式製作並不難,一定數量內不定數量的參數傳入的函式也不難,但是像 printf 或 scanf 系列的函數,並沒有限定要傳入幾個參數,也不限定傳入參數的形式是什麼,這樣的函數要怎麼實做呢?

2006-09-09 04:59:50 · 1 個解答 · 發問者 Rody 5 in 電腦與網際網路 程式設計

感謝 novus, 但您提到 -- 系統固定從 stack 配置 4 個 bytes.. --
這部份讓我疑惑, 如果固定 4 bytes, 那 long long 或 double 或 string 要怎麼處理? 你可以寫個簡易 sprintf 可以丟一個 double 和字串並存到 char buf[80] 裡面的小範例給我看嗎?

2006-09-09 09:23:27 · update #1

感謝, 根據您的範例, 我想確認一下, va_arg(arg, type) 這巨集是否每呼叫一次, arg 就會指向下個引數, 而且不論型別? 那如果型別出錯會怎樣? 如果引數不足又會怎樣?

2006-09-09 18:44:23 · update #2

真是太感謝了, 最後補充兩個小疑問, 第一, 這種 ... 的參數傳遞方式有可能被再次傳遞嗎? 例如我想替 string 類別增加類似 format 功能, 有可能寫個 myformat( string InString,const char *format, ...), 然後在裡面直接把除了第一個以外的引數傳入 sprintf 進行處理嗎? 第二, 你可以另外開個網址寫程式碼給別人看, 這怎麼做到的? 要申請什麼嗎?
最後, 非常感謝您的回答

2006-09-10 07:05:04 · update #3

咦~~有「C++的地下標準程式庫」這東西啊?去哪邊找呢?我就是覺得類似 printf 之類的作法比較簡易, 本來想說如果 string 不提供類似函式, 想要自己來實做了 (其實 MFC 的 CString 和 QT 的 QString 都有類似的東西, 但為了一個格式化就要被這束縛, 感覺很差啊~~)

2006-09-10 10:15:53 · update #4

1 個解答

1.在C語法支援函數宣告中加入"..."來代表不定參數2.在( in C++)當中有三個macrotype va_arg(va_list argptr, type);void va_start(va_list argptr, last_parm);void va_end(va_list argptr);和一個va_list型態,可以協助使用不定參數3.範例#include #include #include double Sum(int num, ...) {   double result = 0;   va_list arg;        va_start(arg, num);   for( ; num > 0; num--) {      result += va_arg(arg, double);   }              va_end(arg);   return result;}             int main() {               double r = Sum(3, 3.0, 2.0, 1.0);   double s = Sum(4, 1.1, 2.2, 3.3, 4.4);      printf("r = %f \t s = %f \n", r, s);   system("pause");   return( 0 );}                 >>...也不限定傳入參數的形式是什麼...事情的真相是,不論你push進來的東西多大,參數在內部還是會遵守某種記憶體對齊的規則。也就是說不論你丟進來的是int、char、double,系統都會固定從stack當中配4 byte(視環境而定,也可能是其他大小)。所以像int printf(const char *format, ...);他根本不知道你丟了多少個參數,也完全不曉得參數的型態。只知道從format字串剖析regular expression,然後去跟stack提取參數,然後照regular expression去詮釋這個記憶體到底是什麼玩意。所以你只要在format撒點小謊,就可以將可憐的printf騙得團團轉

2006-09-09 16:55:02 補充:
4 byte只是舉個例子,實際上有可能是8 byte或其他,要看環境如何實作對於超過一個單位的型態,可以在va_arg當中作一些處理。例如VC6的stdarg.h實作(可以看出是以sizeof(int)為單位):#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

2006-09-09 17:02:10 補充:
我寫了一個勉強可用sprintf
不過這裡po不下
我另外再想辦法補給你吧

2006-09-09 18:01:40 補充:
http://home.pchome.com.tw/online/snomel/args.htm

2006-09-10 01:36:34 補充:
是的,會指向下個引數
如果你願意研究一下我下午在答案裡所補充的VC6實作,應該會更清楚
gcc的實作很容易取得,雖然寫法不同,道理卻差不多

超過引數數目,就像超出陣列範圍或張君雅小妹妹的泡麵爛掉一樣,C是概不負責。
不過既然發生在stack裡面,大概猜得到是其他函數的區域變數、參數或呼叫返回位址之類的。

如果型態不對,則會將stack裡的二進位值reinterpret
例如0xFFFFFFC4
當成int為-60
當成unsigned int為4294967236
double.....因為有64位元,所以會提取兩倍int大小的記憶體,用IEEE浮點數規則解讀

2006-09-10 13:37:44 補充:
1.再傳遞當然沒有問題,你可以參考標準程式庫裡面的vsprintf

2.std::string雖然缺乏regular expression的相關功能
但C++的string stream也相當夠用了
(1)比C的格式化IO安全(型態在編譯期就確定了)
(2)更有彈性(能和其他物件任意搭配、結合STL的iterator和algorithm作出神奇的應用)
(3)效率更好(理論上...因為不像格式化IO一樣還要剖析格式字串。但似乎還沒有哪家的stream真正超越格式化IO)
(4)至少程式碼比較好看

2006-09-10 13:44:49 補充:
如果你真的非常需要std::string的formatter,可以找有著「C++的地下標準程式庫」頭銜的boost,犯不著自己動手

那只是普通的網頁空間
我的編輯軟體能夠將程式碼輸出成彩色html

2006-09-11 12:58:26 補充:
boost 的 format 程式庫
http://www.boost.org/libs/format/doc/format.html

一個勉強可用的_sprintf
void _sprintf(string &ss, const char *fmt, ...)
{
char buf[80];
va_list arg;
va_start(arg, fmt);
vsprintf(buf, fmt, arg);
va_end(arg);
ss = buf;
}

2006-10-03 17:05:57 補充:
補充
C library對於字串的安全性都不盡理想
這也是許多程式的漏洞所在

終於找到的文章:P
http://www.gotw.ca/publications/mill19.htm

2006-09-09 07:12:35 · answer #1 · answered by novus 6 · 0 0

fedest.com, questions and answers