2012-07-30 54 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")