2012-07-30 56 views
3

我想讓人們停止使用像sprintf這樣的函數,因爲它被認爲是不安全函數。如果在代碼中使用sprintf或其他任何技巧,是否存在編譯錯誤的編譯方式?編譯方式停止使用某些C系統調用

+2

哪個編譯器?我已經看到至少有一個編譯器(我認爲這是一個微軟,但不記得確切)警告這樣的事情。作爲一般慣例,我傾向於爲每個編譯器提供嚴格的警告。 – Mawg 2012-07-30 10:02:51

+1

正如@Mawg所說,編譯時具有最高的警告級別,並將警告作爲錯誤提供此功能。在Visual Studio中,編譯器標誌是'/ W4/WX',而gcc(I _think_)是'-Werror -Wall'。 – hmjd 2012-07-30 10:08:40

+1

你的意思是「不健康」嗎?我認爲這是「sfinae」。但是你需要爲此升級到C++。 – 2012-07-30 10:20:10

回答

5
#define sprintf COMPILE_TIME_ERROR 
#define COMPILE_TIME_ERROR switch(0){case 0:case 0:;} 

int main(void) { 
char hi[50]; 
sprintf(hi,"hi"); 
return 0; 
} 

編譯器的輸出將是這樣的:

prog.c: In function ‘main’: 
prog.c:6: error: duplicate case value 
prog.c:6: error: previously used here 
+1

儘管它很糟糕,但它適用於所有編譯器。 +1。 – ArjunShankar 2012-07-30 10:24:12

+0

+1這就是我要發佈的答案。編譯時間斷言是不可思議的事情,並不經常使用imo。 – Mawg 2012-07-30 10:24:45

+0

#error有什麼問題... – thang 2015-02-22 22:43:16

0

是。

您將LD_PRELOAD設置爲庫列表,並且所有這些庫都將先於其他庫加載。您可以定義您需要覆蓋的函數,將該文件設爲共享庫,將該變量設置爲該lib的名稱,然後運行您的可執行文件。

8

GCC supports this sort of thing#pragma GCC poison。使用該標識符後跟一列標識符將導致在程序中使用任何的標識符來引發錯誤。例如,該程序將不編譯:

#include <stdio.h> 

#pragma GCC poison fprintf sprintf 

int main (void) 
{ 
    char foo[100]; 
    sprintf (foo, "bar"); 
    return 0; 
} 

如果宏定義pragma擴展到標識符,則該次數將不再中毒。例如,該程序可以編譯:

#include <stdio.h> 

#define print_to_string sprintf 
#pragma GCC poison sprintf 

int main (void) 
{ 
    char foo[100]; 
    print_to_string (foo, "bar"); 
    return 0; 
} 
0

不是一個答案,但我太愚蠢知道如何發佈格式代碼的答覆。

IMO,@myrkos給出了這個問題的正確答案。

但是,他提到編譯時錯誤,我也想概括一個compile time assert(又名static assert)。

谷歌這些條款,你會得到一堆建議。取決於你的編譯器,有些編譯器會給出比其他編譯器更令人滿意的錯誤信息,所以建一個小的測試程序。我個人(因人而異)喜歡這個一個與海灣合作委員會(道歉原作者,因爲我不記得我是從「借」 - 這是很久以前,它仍然成爲我很好):

/** A "static assert", which checks a condition at compile time, rather 
* than run time. The sooner problems are found, the sooner they can be fixed 
* (and with less effort). 
* 
* Use this one where you don't even want the code to begin running 
* if something is wrong. If you don't use this, you need a test case, 
* but sometimes tests don't get run, so use this for the sort of thing 
* that should never be released to the customer (or even the test department). 
* 
* Example: ASSERT_AT_COMPILE_TIME(1==2), one_does_not_equal_two); 
*   gives this error message under GNU on Linux: 
*    size of array one_does_not_equal_two is negative 
* 
* Note: this is very useful checking the size of user defined types, like uint64_t 
* or for doing things like this: 
* 
* struct foo { 
*  int x; 
*  int y; 
* }; 
* ASSERT_AT_COMPILE_TIME(offsetof(struct foo, y) == 4, y_is_at_offset_4); 
*/ 
#define ASSERT_CAT1(x) ASSERT_CAT ## x 
#define ASSERT_CAT0(x) ASSERT_CAT1(x) 
#define ASSERT_AT_COMPILE_TIME(expression, message) \ 
     struct ASSERT_CAT0(__LINE__) {char message[2*!!(expression)-1]; } 
3

其他人提到觸發編譯錯誤。

不幸的是,如果你想區分錯誤,錯誤信息往往不是非常明確。好事做的是有一個名字一個未定義的對象嵌入了錯誤信息,如:

#define sprintf (do_not_use_sprintf_call = 0) 

所以當sprintf被稱爲gcc錯誤信息將更加明確:

tst.c: In function `main': 
tst.c:11: error: `do_not_use_sprintf_call' undeclared (first use in 
this function) 
tst.c:11: error: (Each undeclared identifier is reported only once 
tst.c:11: error: for each function it appears in.) 

請注意,使用C11,您也可以使用靜態聲明來獲得自己的錯誤消息:

#define sprintf _Static_assert(0, "do_not_use_sprintf_call")