我希望人们停止使用类似的功能,sprintf
因为它被认为是不安全的功能。sprintf
如果在代码中使用或任何其他技巧,是否有编译器方法给出编译错误?
5 回答
GCC通过#pragma GCC poison
. 使用此 pragma 后跟标识符列表将导致在程序中使用任何标识符引发错误。例如,这个程序不会编译:
#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;
}
#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
其他人提到触发编译错误。
不幸的是,如果您想区分错误,错误消息通常不是很明确。一件好事是有一个未定义的对象,其名称嵌入错误消息,如下所示:
#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")
是的。
您将 LD_PRELOAD 设置为库列表,所有这些库将在其他库之前加载。您定义需要覆盖的函数,使文件成为共享库,将此变量设置为该库的名称,然后运行您的可执行文件。
不是答案,但我太笨了,不知道如何在回复中发布格式化代码。
IMO,@myrkos 已经给出了这个问题的正确答案。
但是,他谈到了编译时错误,我也想概括为compile time assert
(又名static assert
)。
谷歌这些条款,你会得到一堆建议。根据您的编译器,有些会给出比其他的更令人愉悦的错误消息,因此请制作一个小型测试程序。我个人(ymmv)更喜欢这个带有 GCC 的版本(向原作者道歉,因为我不记得我从哪里“借来”它 - 这是很久以前的事了,它仍然对我有用):
/** 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]; }