如何为我的自定义函数生成非null参数的警告?

时间:2017-02-04 02:16:17

标签: c gcc

我正在尝试编写一个库函数,其中参数不应该为null,并希望gcc在某些人尝试传递NULL时应该生成警告。我的代码是

#include <stdio.h>
#include <string.h>
int own_strcmp(const char *str1, const char *str2)
{
        if( str1 == NULL || str2 == NULL){
            if(str1 == NULL && str2 == NULL) 
                return 0;
            else if( str1 == NULL)
                return str2[0];
            else
                return str1[0];
        }
        int i=0;
        while(str1[i] && str2[i]){
                if( str1[i] != str2[i]){
                        break;
                }
                i++;
        }
        return str1[i]-str2[i];
}



int main(int argc, char *argv[]){
        const char *str1 = "hello";
        const char *str2 = "hello";
        printf("%s and %s is %d\n", str1, str2, own_strcmp(NULL, str2));
        printf("%s and %s is %d\n", str1, str2, strcmp(NULL, str2));
        return 0;
}

用于标准库的strcmp,用于生成警告。但对于我的功能,它不是。

rajesh@ideapad:~$ gcc own_strcmp.c
own_strcmp.c: In function ‘main’:
own_strcmp.c:21:2: warning: null argument where non-null required (argument 1) [-Wnonnull]
  printf("%s and %s is %d\n", str1, str2, strcmp(NULL, str2));
  ^

2 个答案:

答案 0 :(得分:4)

也许宣称GCC nonnull function attribute正是您要找的。您可以指定所有指针参数都应为非null,或者您可以提供一个参数列表,指定哪些参数应为非null。

我读取文档的方式,如果声明了Arraylist属性,则将空指针传递给非null参数是未定义的行为。必须启用nonnull选项才能收到警告。启用警告后,如果将-Wnonnull传递给非null参数,则会发出警告。但是,对于传递的空指针变量不会发出警告。因此,在运行时处理错误输入很重要。感谢@alk指出这个重要问题。

看起来像Clang also supports this attribute。 Clang还具有可空性类型限定符NULL,但这在GCC中不可用。

我应该强调的是,C标准不支持这种行为,而是编译器扩展。为了便于携带,您应该在运行时通过精心设计的功能处理错误的输入。

这是使用属性声明的函数(没有_Nonnull指针检查的早期版本)。我添加了一行调用NULL并使用空指针变量;请注意,此行会导致发出警告。另请注意,使用空指针变量调用标准库own_strcmp()无法触发警告。

strcmp()

以下是调用GCC后的输出:

#include <stdio.h>
#include <string.h>

int own_strcmp(const char *str1, const char *str2)__attribute__((nonnull));

int main(void)
{
    const char *str1 = "hello";
    const char *str2 = "hello";
    const char *arg = NULL;

    /* Warning issued for this NULL argument */
    printf("%s and %s is %d\n", str1, str2, own_strcmp(NULL, str2));

    /* No warning issued for the NULL variable arg */
    printf("%s and %s is %d\n", str1, str2, own_strcmp(arg, str2));

    /* No warning issued for strcmp() either */
    printf("%s and %s is %d\n", str1, str2, strcmp(arg, str2));    
    return 0;
}

int own_strcmp(const char *str1, const char *str2)
{
    int i=0;
    while(str1[i] && str2[i]){
        if( str1[i] != str2[i]){
            break;
        }
        i++;
    }
    return str1[i]-str2[i];
}

答案 1 :(得分:0)

C有一个声明指针参数的方法,该参数不能为null。但是,它不能保证永远不会传递空指针。它建议编译器可以编译例程,期望参数永远不会为null,但它不一定会阻止调用例程错误地传递null。编译器可能会检测到对此类例程的一些不正确的调用,并发出有关它们的警告或错误,但无法检测到其他例程。

这是通过将static关键字放在参数声明中的很少使用的语法来完成的:

void foo(int p[static 1])
{
    … body of function …
}

这表明p必须提供对至少一个元素的数组的第一个元素的访问权限,根据C 2011 [N1570] 6.7.6.3 7.因为必须有一个元素p点,p可能不为空。例如,编译此代码时:

#include <stddef.h>

void foo(int p[static 1])

void bar(void) { foo(NULL); }

使用带有默认开关的Apple LLVM 9.0.0(clang-900.0.39.2),编译器警告:

x.c:5:18: warning: null passed to a callee that requires a non-null argument
      [-Wnonnull]
void bar(void) { foo(NULL); }
                 ^   ~~~~
x.c:3:14: note: callee declares array parameter as static here
void foo(int p[static 1]) {}
             ^~~~~~~~~~~

但是,此代码编译时没有警告:

#include <stddef.h>

void foo(int p[static 1]) {}

void bar(int *p) { foo(p); }

void baz(void) { bar(NULL); }

因此,只有在直接传递此参数时,此编译器才能检测到此类参数的错误传递。