無參函式的應用與限制
阿新 • • 發佈:2018-12-09
無參函式的應用與限制
在 C90 標準中,你可以宣告一個無引數資訊的函式。一個示例如下:
void no_arg_func();
使用空的小括號來表示沒有引數資訊,編譯器無法獲取到引數資訊,也就不會進行引數檢查,因此你可以傳遞任意數量的引數。下面是一個具體的應用。
#include <stdio.h> #include <stdarg.h> #define MAXARGC 2 #define TEST_BEGIN() \ printf("some variable initialized, or something else\n") #define TEST_END() \ printf("some teardown procedure, or something else\n"); /* function prototype */ extern int init_data(const char *name, int id); extern char *find_name(int id); extern int find_id(const char *name); extern int destroy_data(int id); typedef void (*func_t)(); extern void execute_a_test(func_t text_func, int count, ...); int main(int argc, char *argv[]) { execute_a_test((func_t)init_data, 2, "test", -5); execute_a_test((func_t)find_name, 1, -5); execute_a_test((func_t)find_id, 1, "test"); execute_a_test((func_t)destroy_data, 1, -5); return 0; } int init_data(const char *name, int id) { printf("name is %s, id is %d, %s\n", name, id, __func__); } char *find_name(int id) { printf("id is %d, %s\n", id, __func__); } int find_id(const char *name) { printf("name is %s, %s\n", name, __func__); } int destroy_data(int id) { printf("id is %d, %s\n", id, __func__); } void execute_a_test(func_t test_func, int count, ...) { long argument[MAXARGC]; int i = 0; va_list ap; if (test_func == NULL) { return; } va_start(ap, count); for (; i < count; i++) { argument[i] = va_arg(ap, long); } va_end(ap); TEST_BEGIN(); (*test_func)(argument[0], argument[1]); TEST_END(); }
在上面的程式碼中,我需要測試四個函式,這四個函式的測試過程大同小異,它們最大的區別在於引數個數的不同。在這裡我使用無參函式將四個待測試函式強轉後作為引數傳入到 execute_a_test 中,通過可變長引數統一不同引數,以最長的引數個數來呼叫函式,不區分指標與值,由於 test_func 沒有引數資訊,因此我們可以傳遞任意個數的引數,多餘的引數子函式不會使用,不會造成問題。
execute_a_test 函式可以進行如下修改:
void execute_a_test(func_t test_func, int count, ...) { long argument[MAXARGC]; int i = 0; va_list ap; if (test_func == NULL) { return; } va_start(ap, count); for (; i < count; i++) { argument[i] = va_arg(ap, long); } va_end(ap); TEST_BEGIN(); if (count == 1) { (*test_func)(argument[0]); } else if (count == 2) { (*test_func)(argument[0], argument[1]); } TEST_END(); }
這個修改避免了傳遞多餘引數的問題,但是加入的條件分支會降低程式的效能。
無參函式是 c 語言的舊標準中支援的特性,新標準雖然能夠相容舊標準,但最好不要使用無參函式。這樣我們對上述程式再次進行修改,改為不使用無參函式的實現。
#include <stdio.h> #include <stdarg.h> #define TEST_BEGIN() \ printf("some variable initialized, or something else\n") #define TEST_END() \ printf("some teardown procedure, or something else\n"); /* function prototype */ extern int init_data(const char *name, int id); extern char *find_name(int id); extern int find_id(const char *name); extern int destroy_data(int id); typedef int (*func_one)(long); typedef int (*func_two)(long, long); extern void execute_a_test(func_two func, long arg1, long arg2); extern void execute_one_arg_functest(func_one func, long arg); extern void execute_two_arg_functest(func_two func, long arg1, long arg2); int main(int argc, char *argv[]) { execute_a_test((func_two)init_data, (long)"test", (long)-5); execute_a_test((func_two)find_name, (long)-5, (long)0); execute_a_test((func_two)find_id, (long)"test", (long)0); execute_a_test((func_two)destroy_data, (long)-5, (long)0); execute_two_arg_functest((func_two)init_data, (long)"test", (long)-5); execute_one_arg_functest((func_one)find_name, (long)-5); execute_one_arg_functest((func_one)find_id, (long)"test"); execute_one_arg_functest((func_one)destroy_data, (long)-5); return 0; } int init_data(const char *name, int id) { printf("name is %s, id is %d, %s\n", name, id, __func__); } char *find_name(int id) { printf("id is %d, %s\n", id, __func__); } int find_id(const char *name) { printf("name is %s, %s\n", name, __func__); } int destroy_data(int id) { printf("id is %d, %s\n", id, __func__); } void execute_a_test(func_two func, long arg1, long arg2) { if (func == NULL) { return; } TEST_BEGIN(); (*func)(arg1, arg2); TEST_END(); } void execute_one_arg_functest(func_one func, long arg) { if (func == NULL) { return; } TEST_BEGIN(); (*func)(arg); TEST_END(); } void execute_two_arg_functest(func_two func, long arg1, long arg2) { if (func == NULL) { return; } TEST_BEGIN(); (*func)(arg1, arg2); TEST_END(); }
上面的程式碼中,使用了多次強轉,這是一大不足。實際上可以將指標與值分開,編寫單獨的函式,但這樣又會增強程式碼的耦合度。寫來寫去還是覺得使用可變長引數可能更好點!最終版函式如下:
void execute_a_test(func_t test_func, int count, ...)
{
long argument[MAXARGC];
int i = 0;
va_list ap;
if (test_func == NULL) {
return;
}
va_start(ap, count);
for (; i < count; i++) {
argument[i] = va_arg(ap, long);
}
va_end(ap);
TEST_BEGIN();
if (count == 1) {
(*(func_one)test_func)(argument[0]);
} else if (count == 2) {
(*(func_two)test_func)(argument[0], argument[1]);
}
TEST_END();
}