2017-02-04 3 views
0

Я пытаюсь написать библиотечную функцию, где аргументы не должны быть нулевыми, и хотите, чтобы 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 стандартной библиотеки используется для генерации предупреждений. но для моей функции это не так.

[email protected]:~$ 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)); 
^
+0

Почему бы просто не манипулировать входами «NULL» в функции? –

+0

Надежность значений «null» означает, что компилятор решил проблему с остановкой. Самое маловероятное. Почему вы ожидаете, что gcc сможет? Если вы хотите создать такой код, C не является вашим языком. – Olaf

+0

@DavidBowling Я могу это сделать, но я хочу, чтобы предупреждение отображалось пользователю, чтобы оно могло быть лучше для пользователя моей библиотеки. – rajesh6115

ответ

4

Возможно, объявление GCC nonnull function attribute - это то, что вы ищете. Вы можете указать, что все аргументы указателя должны быть не пустыми, или вы можете предоставить список аргументов, определяющий, какие аргументы должны быть не пустыми.

Способ, которым я читал документы, если объявлен атрибут nonnull, это неопределенное поведение для передачи нулевого указателя на ненулевой параметр. Для получения предупреждения необходимо включить параметр -Wnonnull. С включенными предупреждениями, если NULL передается на ненулевой параметр, выдается предупреждение. Но, не будет выдано предупреждение за переменную нулевого указателя, которая передается. Таким образом, важно обрабатывать неверный ввод во время выполнения. Благодаря @alk для указания этой важной проблемы.

Похоже, Clang also supports this attribute. Clang также имеет классификатор типа nullability _Nonnull, но он недоступен в GCC.

Я должен подчеркнуть, что это поведение не поддерживается в стандарте C, но скорее является расширением компилятора. Для переносимости вы должны обрабатывать неверные входы во время выполнения с хорошо продуманными функциями.

Ваша функция (более ранняя версия без NULL указателей указателей), объявленных атрибутом. Я добавил строку, которая вызывает own_strcmp() с нулевой переменной указателя; обратите внимание, что эта строка не выдает предупреждение. Также обратите внимание, что вызов стандартной библиотеки strcmp() с нулевой переменной-указателем не может вызвать предупреждение.

#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]; 
} 

Вот выход после вызова GCC:

λ> gcc -std=c11 -Wall -Wextra -Wpedantic warning_gcc_42035769.c 
warning_gcc_42035769.c: In function ‘main’: 
warning_gcc_42035769.c:13:5: warning: null argument where non-null required (argument 1) [-Wnonnull] 
    printf("%s and %s is %d\n", str1, str2, own_strcmp(NULL, str2)); 
    ^
+1

Можете добавить примечание, что в стандартном C это невозможно. То, что вы описываете, - это расширение gcc (и clang). Другие компиляторы не обязаны его поддерживать. В стандарте C лучше, чтобы функция проверяла/утверждала ненулевые аргументы, хотя это проверки времени выполнения. – Peter

+0

@ Питер ... да, я мог бы быть более ясным об этом. Я уточню свой ответ. Спасибо за комментарий. –

+1

В качестве другого примечания к OP: это предупреждение в большинстве случаев никогда не будет выдано, если вы передадите переменные функции. – alk

0

С имеет метод для объявления параметра указателя, который не должен быть нулевым. Однако он не может гарантировать, что нулевой указатель никогда не передается с ошибкой. Он советует компилятору, что он может скомпилировать подпрограмму в ожидании того, что параметр никогда не будет нулевым, но это не обязательно предотвратит неправильное обращение вызовов от 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 (лязг-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); } 

Так что, кажется, этот компилятор может обнаружить, что нуль неправильно передается для такого параметр только тогда, когда он передается напрямую.

+0

Это кажется ненадежным. [Этот тест] (https://ideone.com/LXVF98) с использованием Clang 4.0 на Ideone, по-видимому, оптимизируется по мере вашего описания, но [этот] (https://ideone.com/bNrr3Q) с использованием GCC 6.3 на Ideone не , У меня нет Clang, установленного в моей системе прямо сейчас, но когда я скомпилировал этот код с помощью GCC, никаких предупреждений не было. –

Смежные вопросы