2016-03-17 2 views
0

Это, скорее всего, вопрос стиля и традиций кода, но вопрос в следующем.Проверка аргументов перед вызовом функции, известной для проверки самих аргументов

Давайте предположим, что у нас есть функция, которая проверяет аргументы, например:

int do_something(int * arr) { 
    if (arr == NULL) { 
     printf("arr is NULL\n"); 
     return -1; 
    } 
    ... 

Теперь мы будем использовать его. Вопрос: мы должны проверить аргумент, который мы собираемся передать ему? Ибо это все равно проверит.

Пример довольно упрощен, сценарии реальной жизни могут быть намного сложнее, с большим количеством аргументов (и более сложными проверками) и дополнительными дополнительными накладными расходами, вызванными вызовом функции - если это, скажем, какой-то IPC.

Таким образом, более общий вопрос: каковы общие принципы и практика в отношении таких ситуаций?

+1

Существует только один ответ: это зависит. –

+0

Вы должны, вероятно, сделать разумные тесты в вызывающем. Если вызываемая функция находится в одной и той же единице перевода (или используется LTO), дублированный тест может быть оптимизирован компилятором, и если вызываемая функция * not * в той же системе перевода, вам не нужно будет проверять больше, чем прототип функции, чтобы иметь возможность его вызвать. – EOF

+0

@ MichaelWalz, но что я должен обратить внимание и рассмотреть? – olegst

ответ

2

Это будет основано на личном опыте и предвзятости. Несмотря на это, здесь он идет:

  1. Если do_something принадлежит к библиотеке и открыта для пользователей библиотеки как функции, которые они могут позвонить непосредственно, то лучше иметь какие-либо и все проверки, необходимые, чтобы убедиться, что do_something прочный.

  2. Если это внутренняя функция в библиотеке, все же лучше всего иметь все необходимые проверки, чтобы убедиться, что do_something является надежным. Единственное исключение, которое я сделал бы, а не делать проверки, - это если на производительность программы/библиотеки негативно повлияли проверки.

  3. Если это функция в вашем собственном приложении, все же лучше всего иметь все и все проверки, необходимые для обеспечения надежной работы do_something. Единственное исключение, которое я сделал бы, а не делать проверки, - это если на производительность программы/библиотеки негативно повлияли проверки.

0

Если функция задокументирована как проверяющая параметр, то вызовите ее без проверки. Для примера free() явно документированы как принятие NULL в качестве параметра, нет, поэтому нет смысла писать слишком часто видел

if(p != NULL) 
    free(p); 

Это захламление ваш код не приносит никакой пользы. Усиление избежания ненужных вызовов обычно полностью устраняется в шуме.

Конечно, вам нужно будет проверить возвращаемое значение вашей функции.

Если вы являетесь исполнителем своей функции, будь то библиотечная функция или только локальная вспомогательная функция, то даже некоторые компиляторы могут комментировать конкретный контракт вашей функции.

Если, например, ваша функция не принимает указатель NULL, вы можете установить (on gcc) __attribute__((nonnull)) при объявлении функции.

Если объявить, например:

int do_something(int * arr) __attribute__((nonnull (1))); 

вы знаете, что вы не можете вызвать функцию с NULL (и компилятор даже предупредить, если он знает, что вы делаете). Но будьте осторожны, этот атрибут может удивлять моментами. Если вы объявите его так, как я, и вы все равно проверите параметр, как в своем примере, вы можете обнаружить, что оптимизатор полностью удаляет чек из объектного кода.

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