3

我希望人们停止使用类似的功能,sprintf因为它被认为是不安全的功能sprintf如果在代码中使用或任何其他技巧,是否有编译器方法给出编译错误?

4

5 回答 5

8

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;
}
于 2012-07-30T10:17:50.677 回答
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
于 2012-07-30T10:15:37.997 回答
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")
于 2012-07-30T11:03:16.807 回答
0

是的。

您将 LD_PRELOAD 设置为库列表,所有这些库将在其他库之前加载。您定义需要覆盖的函数,使文件成为共享库,将此变量设置为该库的名称,然后运行您的可执行文件。

于 2012-07-30T10:16:05.687 回答
0

不是答案,但我太笨了,不知道如何在回复中发布格式化代码。

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]; }
于 2012-07-30T10:35:08.067 回答