程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言可變參數在宏定義中的應用

C語言可變參數在宏定義中的應用

編輯:關於C語言

C語言可變參數在宏定義中的應用


在C語言的標准庫中,printf、scanf、sscanf、sprintf、sscanf這些標准庫的輸入輸出函數,參數都是可變的。在調試程序時,我們可能希望定義一個參數可變的輸出函數來記錄日志,那麼用可變參數的宏是一個不錯的選擇。

C99中規定宏也可以像函數一樣帶可變的參數,如:

#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)
其中,...表示可變參數列表,__VA_ARGS__在預處理中,會被實際的參數集(實參列表)所替換。
同時gcc還支持帶可以變參數名的方式(注意:VC不支持):

#define LOG(format, args...) fprintf(stdout, format, args)
同樣,args在預處理過程中,會被實際的參數集所替換。其用法和上面的方式一樣,只是參數的符號有變。

需要注意的是,上述兩種方式的可變參數不能省略,盡管可以傳一個空參數進去。說到這裡,有必要提一下“##”連接符號的用法,“##”的作用是對token進行連接,上例中format,args,__VA_ARGS都可以看作是token,如果token為空,“##”則不進行連接,所以允許省略可變參數。對上述2個示例的改造:

#define LOG(format, ...) fprintf(stdout, format, ##__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, ##args)
即然參數可以省略,那麼用宏定義一個開關,實現一個輸出日志的函數就簡單了:

#ifdef DEBUG
#define LOG(format, ...) fprintf(stdout, ">>>>>" format "<<<<", ##__VA_ARGS__)
#else
#define LOG(format, ...)
#endif
在開發階段時,在編譯選項中加入一個DEBUG宏,即會在程序中使用了LOG宏的地方輸出日志,否則只是調用了一個空的LOG宏而已,不會有任何輸出。假設源文件為test.c,gcc編譯時加上-DDEBUG(-D表示預定宏,在預編譯的時候由編譯器定義)即在判斷DEBUG宏時條件成立,從而達到輸出日志的目的:

gcc -o test test.c -DDEBUG

示例:在Android的NDK開發中,打印log的宏:

需要在android.mk文件中加載日志模塊,並添加DEBUG選項:

LOCAL_LDLIBS 	:= -llog	#添加日志模塊
LOCAL_CFLAGS	+= -DDEBUG

NDKTest.cpp

#include 
#include 

#define LOG_TAG "HelloNDK"
#ifdef DEBUG
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
#define LOGI(...) do{} while(0)
#define LOGD(...) do{} while(0)
#define LOGE(...) do{} while(0)
#endif

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
	JNIEnv *env;
	jclass cls;
	if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK)
	{
		LOGE("init javavm failed!");
		return JNI_ERR;
	}
	cls = env->FindClass("com/learn/ndk/SampleModel");
	if (cls == NULL)
	{
		LOGE("can't find com.learn.ndk.SampleModel.");
		return JNI_ERR;
	}
	class_com_learn_ndk_MainActivity = (jclass)env->NewWeakGlobalRef(cls);
	env->DeleteLocalRef(cls);
	return JNI_VERSION_1_4;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved