この質問はgccコンストラクターに関するもので、コンパイルとリンクは正しいですが、実行されません。
交流があります:
UTEST_BEGIN()
UID(a_test)
{
printf("a test");
return true;
}
UTEST_END(a)
bc も同様です。
UTEST_BEGIN()
UID(b_test)
{
printf("b test");
return true;
}
UTEST_END(b)
コード オブジェクトは、いくつかのテスト関数にリンクする UID() を使用しています。私の最初のバージョンでは、UID() を囲むために UTEST_BEGIN() UTEST_END() を追加しました。最後に、UTEST_BGIN() UTEST_END() が必要ではないことに気付きました。変更すると、予期しない結果が得られます。
UTEST_BEGIN()、UID()、UTES_END() の定義を変更すると、異なる結果が得られました。
基本的なアイデアはcan-i-auto-collect-a-list-of-function-by-c-macroから来ています!
テスト 1:
#define UTEST_BEGIN() \
static const bool __m_en = true; \
static struct __uti *__m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
bool unit_test_item_pump_do(int file_id, bool (*f)(void), const char *f_name);
#define UTEST_END(file_name) \
bool unit_test_##file_name(void) \
{ \
if (!__m_en) \
return true; \
struct __uti *cur; \
for(cur = __m_uti_head; cur; cur = cur->next) { \
unit_test_set_run_last_line(__LINE__); \
if (!unit_test_item_pump_do(this_file_id, cur->f, cur->f_name)) \
return false; \
} \
return true; \
}
正しい結果が得られました。リンクから __uti_a_test() と __uti_b_test() を呼び出すことができます。実際、__uti_xxx() リンクは __m_uti_head と関連付けられていないため、UTEST_BEGIN() と UTEST_END() を削除したいと考えています。
gcc -E ac を実行すると、マクロは次のように拡張されます。
static const bool __m_en = 1;
static struct __uti *__m_uti_head = ((void *)0);
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
bool unit_test_a(void)
{
if (!__m_en)
return 1;
struct __uti *cur;
for(cur = __m_uti_head; cur; cur = cur->next) {
unit_test_set_run_last_line(19);
if (!unit_test_item_pump_do(file_id_a, cur->f, cur->f_name))
return 0;
}
return 1;
}
テスト 2:
#define UTEST_BEGIN()
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
#define UTEST_END(file_name)
UID() の定義はテスト 1 と同じです。 UTEST_BEGIN() と UTEST_END() は空白のままにします。コンパイルとリンクは正しいが、uti_construct_a_test() と uti_construct_b_test() は実行されない。
gcc -E ac を実行すると、マクロは次のように拡張されます。
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
utest_item_list_add_global() は他の .c ファイルに存在し、関数はノードをリンクに追加します。
static struct __uti *m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti)
{
if (NULL == m_uti_head) {
m_uti_head = uti;
return true;
}
struct __uti *tail = m_uti_head;
while (NULL != tail->next)
tail = tail->next;
tail->next = uti;
return true;
}
展開されたマクロは正しいようです。問題はリンク段階にあると思いますが、そうですか?