Эффективный С. Профессиональное программирование [Роберт С. Сикорд] (pdf) читать постранично, страница - 91

-  Эффективный С. Профессиональное программирование  (пер. А. Павлов) (и.с. Библиотека программиста) 6.38 Мб, 304с. скачать: (pdf) - (pdf+fbd)  читать: (полностью) - (постранично) - Роберт С. Сикорд

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

оказывает на идентификатор никакого влияния,
если ему уже была назначена какая-то компоновка.
Объявления с конфликтующими компоновками могут вызывать неопределенное поведение; более подробную информацию об этом можно получить
в правиле DCL36-C стандарта CERT C (не объявляйте идентификатор
с конфликтующими классами компоновки).
В табл. 10.1 показаны примеры объявлений с явной и неявной компоновкой.
Таблица 10.1. Примеры явной и неявной компоновки
Косвенная и ручная компоновка
foo.c
void func(int i) { // Неявная внешняя компоновка
// у i нет компоновки
}
static void bar(void); // Внутренняя компоновка, bar не из bar.c
extern void bar(void) {
// bar по-прежнему имеет внутреннюю компоновку, так как начальное
// объявление было статическим; спецификатор extern в данном случае
// ни на что не влияет
}
bar.c
extern void func(int i); // Явная внешняя компоновка
static void bar(void) { // Internal Внутренняя компоновка, bar не из foo.c
func(12); // Вызывает func из foo.c
}
int i; // Внешняя компоновка; не конфликтует с i из foo.c или bar.c
void baz(int k) { // Неявная внешняя компоновка
bar(); // Вызываем bar из bar.c, не foo.c
}

260  

Глава 10. Структура программы (в соавторстве с Аароном Баллманом)

Идентификаторы в вашем публичном интерфейсе должны иметь внешнюю
компоновку, чтобы их можно было вызывать из-за пределов их единицы
трансляции. В то же время идентификаторы, относящиеся к подробностям
реализации, нужно объявлять либо с внутренней компоновкой, либо без
таковой. Обычно, чтобы этого достичь, функции публичного интерфейса
объявляют в заголовочном файле со спецификатором класса хранения
extern или без него (внешняя компоновка назначается объявлениям авто­
матически, но в использовании extern нет никакого вреда) и похожим
образом размещают их определения в исходном файле.
Однако внутри исходного файла все объявления, которые выступают
подробностями реализации, должны содержать спецификатор static;
это позволяет сделать их приватными и доступными только в данном
файле. Вы можете подключить публичный интерфейс, объявленный в заголовочном файле, используя директиву препроцессора #include, чтобы
обратиться к нему из другого файла. Сущности, которые объявлены на
уровне файла и не должны быть видны за его пределами, обычно лучше
делать статическими (static). Этот подход ограничивает загромождение
глобального пространства имен и снижает вероятность непредвиденного
взаимодействия между единицами трансляции.

Структурирование простой программы
Чтобы научиться структурировать настоящие сложные программы, начнем
с несложного примера, определяющего, является ли число простым. Простым называют натуральное число больше 1, которое нельзя получить путем
умножения двух меньших натуральных чисел. Мы напишем два отдельных
компонента: статическую библиотеку, которая будет заниматься проверкой,
и приложение командной строки с пользовательским интерфейсом к ней.
Программа primetest принимает на вход список целочисленных значений, разделенных пробелами, и выводит информацию о том, является ли
каждое из них простым числом. Если какая-либо часть ввода окажется
некорректной, то программа выведет информативное сообщение с описанием того, как пользоваться ее интерфейсом.
Прежде чем приступать к структурированию программы, рассмотрим пользовательский интерфейс. Вначале мы выводим справочную информацию
для программы командной строки, как показано в листинге 10.2.

Структурирование простой программы    261

Листинг 10.2. Вывод справочной информации
// Выводим справочный текст в командной строке
static void print_help(void) {
printf("%s", "primetest num1 [num2 num3 ... numN]\n\n");
printf("%s", "Tests positive integers for primality. Supports testing
");
printf("%s [2-%llu].\n", "numbers in the range", ULLONG_MAX);
}

Функция print_help состоит из трех отдельных вызовов printf, которые
записывают в стандартный вывод текст с объяснением о том, как использовать эту команду.
Аргументы командной строки передаются программе в текстовом виде,
поэтому мы определяем служебную функцию, чтобы преобразовать их
в целочисленные значения, как показано в листинге 10.3.
Листинг 10.3. Преобразование отдельного аргумента
командной строки
// Преобразует строковый аргумент arg в значение unsigned long long,
// на которое ссылается val
// Возвращает true, если преобразование аргументов было успешным,
// и false, если нет
static bool convert_arg(const char *arg, unsigned long long *val) {
char *end;
// strtoll возвращает внутренний индикатор ошибки; очистите errno
// перед вызовом
errno = 0;
*val = strtoull(arg, &end, 10);
//
//
if
if
if

}

Отслеживаем ошибки, когда вызов возвращает контрольное значение
и устанавливает errno
((*val == ULLONG_MAX) && errno) return false;
(*val == 0 && errno) return false;
(end == arg) return false;

// Если мы попали сюда, нам удалось преобразовать аргумент.
// Но мы хотим допускать только
// значения больше 1, поэтомы мы отбрасываем все значения