Вместо того, чтобы критиковать, позвольте мне показать вам пару контрпримеров.Учитывайте следующее:
struct intrange {
int minimum;
int maximum;
};
Эти ограничения включены.Вы можете передавать структуры по значению и назначать их, как и любой другой тип.Чтобы разделить такую структуру, вы можете использовать
struct intrange intrange_split(const struct intrange range,
const int half)
{
/* Midpoint of the range, rounding towards zero */
const int midpoint = (range.minimum + range.maximum) / 2;
struct intrange result;
if (half > 0) {
/* Upper half, including midpoint. */
result.minimum = midpoint;
result.maximum = range.maximum;
} else
if (half < 0) {
/* Lower half, excluding midpoint. */
result.minimum = range.minimum;
result.maximum = midpoint - 1;
} else {
/* No change. */
result = range;
}
return result;
}
. Вышеуказанная функция intrange_split()
принимает в качестве параметра структуру intrange range
и int half
, чтобы указать, как ее разделить.Нет никаких проверок ошибок.
Если вы хотите работать со структурой, переданной по ссылке, вы можете использовать, скажем,
int intrange_split(struct intrange *range, int half)
{
int midpoint;
/* No range? Invalid range? */
if (!range || range->maximum < range->minimum)
return -1; /* Invalid range. */
/* Note: This could overflow. */
midpoint = (range->minimum + range->maximum) / 2;
if (half == 1) {
/* Upper half, including midpoint. */
range->minimum = midpoint;
} else
if (half == -1) {
/* Lower half, excluding midpoint. */
range->maximum = midpoint - 1;
} else {
/* Invalid operation. */
return -1;
}
/* Verify range is valid (non-empty). */
if (range->maximum < range->minimum)
return -1;
/* Range is valid, and not empty. */
return 0;
}
Более распространенное использование возвращаемого значения для представления успеха /ошибка в C, потому что в отличие от C ++, здесь нет исключений.(Вы также можете использовать утверждения или распечатать сообщение об ошибке и abort()
или exit(EXIT_FAILURE)
, в зависимости от того, исправлена ошибка или нет.)
Во всех вышеупомянутых случаях я использовал логику, согласно которой midpoint
находится на полпути между minimum
и maximum
, округленными до нуля;и что midpoint
принадлежит верхнему диапазону.Вы можете выбрать , как вы его определяете, если вы делаете выбор явно, и документировать его.Посмотрите, насколько проще эти подходы?
Также часто используют макросы препроцессора или статические встроенные функции для инициализации переменных.В этом случае, например,
#define INTRANGE_INIT(min, max) { min, max }
static inline struct intrange intrange_define(const int minimum,
const int maximum)
{
struct intrange result = { minimum, maximum };
return result;
}
, чтобы в своем коде вы могли объявить диапазон, используя, например, struct intrange my_range = INTRANGE_INIT(0, 100);
.Конечно, вы можете также инициализировать его, используя struct intrange my_range = { 0, 100 };
или даже struct intrange my_range; my_range = intrange_define(0, 100);
.
Пока реализация читаема и проста для понимания, это нормально.Я предпочитаю предпочитать стиль макроса препроцессора сам, но это чисто вопрос стиля.
Не забывайте писать комментарии, которые описывают ваш дизайн и намерения, а не то, что делает код.Этот навык так же важен, как и само программирование.Вы обнаружите, что в большинстве случаев код, который может быть только написан и не поддерживается, не стоит электричества для его запуска.
(И никогда не привыкать думать, что вы добавите ошибкупроверка и обеспечение безопасности позже. Потому что вы не будете. Никто никогда не делает. Если они пытаются, они неизменно терпят неудачу. Это потому, что надежность и безопасность могут быть только разработаны, а не добавлены впоследствии.)