在MDK中使用$Sub$$和$Super$$的記錄
阿新 • • 發佈:2020-08-05
在MDK開發環境下,對於某些無法被更改的函式,我們需要更改這些函式執行前後的邏輯,偏偏又無法更改到呼叫這些函式並已經被封裝的程式碼,這真是讓人一籌莫展。
幸好MDK給我們留了一個後門,讓我們充分使用“$Sub$$”和“$Super$$”來完成這個目標。
比如某個函式
extern void foo(void);
我們要在它執行的前後進行一段特定的處理,那麼參考下面的程式碼:
/*定義 foo 函式*/ void foo(void) { printf("f()\n"); } /*定義foo的補丁函式*/ void $Sub$$foo(void) { /*需要在 foo() 之前執行的程式碼塊*/ printf("before_foo()\n"); /*呼叫 foo(),要注意使用字首"$Super$$"*/ $Super$$foo(); /*需要在 foo() 之後執行的程式碼塊*/ printf("execute_after_f()\n"); } /* 疑問:我定義 printf 的補丁函式 $Sub$$printf, 實際呼叫 printf 的時候,並沒有進入 $Sub$$printf, 這是為何? */ int $Sub$$printf(const char *fmt, ...) { $Super$$printf("<*> "); return $Super$$printf(fmt); } int main(void) { uint32_t limitedTick; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); tick_initialize(); trace_initialize(user_command_deal); printf("\n execute \"foo();\" result:\n\n"); /* 直接寫作"foo();",理論上應該看到 <*> before_foo(), <*> f(), <*> after_foo() 三行日誌,實際上前面的“<*>”沒有輸出。 也就是說,printf函式的補丁沒生效,foo的補丁生效了。 為什麼呢? */ foo(); /*採用 $Sub$$printf 的形式去呼叫的話就失去意義了。*/ $Sub$$printf("i am printed by \"$Sub$$printf\".\n"); while(1); return 0; }
注意:
1、必須定義一個新的以“$Sub$$”作為字首,後面緊跟“欲被處理的函式名”的函式,例如 “$Sub$$foo()”.
2、在補丁函式裡面需要以 “$Super$$foo()” 的方式去呼叫原始的 foo 函式,而不應該直接寫作 “foo()”去呼叫。
(不要“$Super$$”字首也能呼叫到,不建議這麼做。感覺要是不加字首,就好像進入無限巢狀一樣的,不斷的呼叫自己。)
3、這個特性僅在ARM CC編譯器內被支援,所以一般都會使用巨集“#if defined(__CC_ARM)”來囊括處理。
4、既然是針對 foo 的補丁,在呼叫的地方自然就應該寫作 "foo();",而不是 "$Sub$$foo();",要不然補丁有何意義呢?
疑問:
為什麼我針對printf的補丁不生效呢?
參考:
https://www.cnblogs.com/raswin/p/10031117.html
https://blog.csdn.net/qq_42860728/article/details/89495882