部分代碼如下:
va_start(ap, fmt);
vsprintf(text, fmt, ap);
va_end(ap);
提示錯誤為:_va_start 內部函式只能在 varargs 中
uj5u.com熱心網友回復:
va_start/va_end只能用在C呼叫方式(引數從右至左入堆疊,并由呼叫方釋放堆疊),且引數為變參(傳遞的引數個數不固定)的情形下才有意義。uj5u.com熱心網友回復:
那這個程式有辦法修改嗎?我對進堆疊出堆疊這塊的知識了解的不是很多。
uj5u.com熱心網友回復:
你這個代碼所在的函式原型是什么,貼出來看看。uj5u.com熱心網友回復:
GLvoid COpenglSet::glPrint(const char *fmt, double Cx,double Cy,double Cz)
{
// BuildFont();
float length=0; // Used To Find The Length Of The Text
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) // If There's No Text
return; // Do Nothing
va_start(ap, fmt); // Parses The String For Variables
//vsprintf(text, fmt = va_arg(ap, char*), ap);
vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
for (unsigned int loop=0;loop<(strlen(text));loop++) // Loop To Find Text Length
{
length+=gmf[text[loop]].gmfCellIncX; // Increase Length By Each Characters Width
}
glPushMatrix();
glTranslatef(Cx,Cy,Cz);
glTranslatef(-length/2,0.0f,0.0f); // Center Our Text On The Screen
glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits
glListBase(base); // Sets The Base Character to 0
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text
glPopAttrib();
glPopMatrix();
// Pops The Display List Bits
// KillFont();
}
uj5u.com熱心網友回復:
我以前寫過類似的,大概是這個樣子,供你參考int xxxxxx::printf(const wchar_t *p_wszFormat, ...) {
va_list args;
va_start(args, p_wszFormat);
vsnwprintf(NULL, 0, p_wszFormat, args);
va_end(args);
.........
}
uj5u.com熱心網友回復:
C++的話必須有...引數的函式中使用va_startuj5u.com熱心網友回復:
1樓說的很清楚了。簡單說就是首先函式的呼叫約定要用__cdecl或__stdcall,其次引數要有可變引數"..."
uj5u.com熱心網友回復:
變長引數不能用stdcall
uj5u.com熱心網友回復:
自己試試就知道了。我用了許多年了。
#include <strsafe.h>
void __stdcall TfrmMain::OutputLog(LPCWSTR msg, ...)
{
va_list ap;
va_start(ap, msg);
WCHAR buffer[2048] = { 0 };
StringCchVPrintf(buffer, 2048, msg, ap);
va_end(ap);
if (mmoLog->Lines->Count > 4000)
mmoLog->Lines->Clear();
mmoLog->Lines->Add(buffer);
}
uj5u.com熱心網友回復:
1.在C中,當我們無法列出傳遞函式的所有實參的型別和數目時,可以用省略號指定引數表void foo(...);
void foo(parm_list,...);
這種方式和我們以前認識的不大一樣,但我們要記住這是C中一種傳參的形式,在后面我們就會用到它。
2.函式引數的傳遞原理
函式引數是以資料結構:堆疊的形式存取,從右至左入堆疊。
首先是引數的記憶體存放格式:引數存放在記憶體的堆疊段中,在執行函式的時候,從最后一個開始入堆疊。因此堆疊底高地址,堆疊頂低地址,舉個例子如下:
void func(int x, float y, char z);
那么,呼叫函式的時候,實參 char z 先進堆疊,然后是 float y,最后是 int x,因此在記憶體中變數的存放次序是 x->y->z,因此,從理論上說,我們只要探測到任意一個變數的地址,并且知道其他變數的型別,通過指標移位運算,則總可以順藤摸瓜找到其他的輸入變數。
下面是 <stdarg.h> 里面重要的幾個宏定義如下:
typedef char* va_list;
void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type );
void va_end ( va_list ap );
va_list 是一個字符指標,可以理解為指向當前引數的一個指標,取參必須通過這個指標進行。
<Step 1> 在呼叫引數表之前,定義一個 va_list 型別的變數,(假設va_list 型別變數被定義為ap);
<Step 2> 然后應該對ap 進行初始化,讓它指向可變引數表里面的第一個引數,這是通過 va_start 來實作的,第一個引數是 ap 本身,第二個引數是在變參表前面緊挨著的一個變數,即“...”之前的那個引數;
<Step 3> 然后是獲取引數,呼叫va_arg,它的第一個引數是ap,第二個引數是要獲取的引數的指定型別,然后回傳這個指定型別的值,并且把 ap 的位置指向變參表的下一個變數位置;
<Step 4> 獲取所有的引數之后,我們有必要將這個 ap 指標關掉,以免發生危險,方法是呼叫 va_end,他是輸入的引數 ap 置為 NULL,應該養成獲取完引數表之后關閉指標的習慣。說白了,就是讓我們的程式具有健壯性。通常va_start和va_end是成對出現。
例如 int max(int n, ...); 其函式內部應該如此實作:
#include <iostream.h>
void fun(int a, ...)
{
int *temp = &a;
temp++;
for (int i = 0; i < a; ++i)
{
cout << *temp << endl;
temp++;
}
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
int d = 4;
fun(4, a, b, c, d);
system("pause");
return 0;
}
Output::
1
2
3
4
3:獲取省略號指定的引數
在函式體中宣告一個va_list,然后用va_start函式來獲取引數串列中的引數,使用完畢后呼叫va_end()結束。像這段代碼:
void TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
va_list args;
va_start(args, pszFormat); //一定要“...”之前的那個引數
_vsnprintf(pszDest, DestLen, pszFormat, args);
va_end(args);
}
4.演示如何使用引數個數可變的函式,采用ANSI標準形式
#include 〈stdio.h〉
#include 〈string.h〉
#include 〈stdarg.h〉
/*函式原型宣告,至少需要一個確定的引數,注意括號內的省略號*/
int demo( char, ... );
void main( void )
{
demo("DEMO", "This", "is", "a", "demo!", "");
}
/*ANSI標準形式的宣告方式,括號內的省略號表示可選引數*/
int demo( char msg, ... )
{
/*定義保存函式引數的結構*/
va_list argp;
int argno = 0;
char para;
/*argp指向傳入的第一個可選引數,msg是最后一個確定的引數*/
va_start( argp, msg );
while (1)
{
para = va_arg( argp, char);
if ( strcmp( para, "") == 0 )
break;
printf("Parameter #%d is: %s\n", argno, para);
argno++;
}
va_end( argp );
/*將argp置為NULL*/
return 0;
}
以上是對va_start和va_end的介紹。
uj5u.com熱心網友回復:
呃,雖然編譯過去了,但呼叫方式還是cdecl,編譯器忽略了__stdcall這個關鍵字。
stdcall是被呼叫者恢復堆疊的,變長的話是無法恢復堆疊的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/74420.html
下一篇:bcb6如何加載PNG圖片
