Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C++ для начинающих.pdf
Скачиваний:
199
Добавлен:
01.05.2014
Размер:
3.97 Mб
Скачать

В данном разделе мы видели примеры директивы связывания extern "C" только для языка С. Это единственный внешний язык, поддержку которого гарантирует стандарт С+ +. Конкретная реализация может поддерживать связь и с другими языками. Например, extern "Ada" для функций, написанных на языке Ada; extern "FORTRAN" для языка FORTRAN и т.д. Мы описали один из случаев использования ключевого слова extern в С++. В разделе 8.2 мы покажем, что это слово имеет и другое назначение в объявлениях функций и объектов.

Упражнение 7.14

exit(), printf(), malloc(), strcpy() и strlen() являются функциями из библиотеки С. Модифицируйте приведенную ниже С-программу так, чтобы она компилировалась и

const char *str = "hello";

void *malloc( int );

char *strcpy( char *, const char * ); int printf( const char *, ... );

int exit( int );

int strlen( const char * );

int main()

{/* программа на языке С */

char* s = malloc( strlen(str) +l );

strcpy( s, str );

printf( "%s, world\n", s ); exit( 0 );

связывалась в С++.

}

7.8. Функция main(): разбор параметров командной строки

При запуске программы мы, как правило, передаем ей информацию в командной строке. Например, можно написать

prog -d -o of lie dataO

Фактические параметры являются аргументами функции main() и могут быть получены из массива C-строк с именем argv; мы покажем, как их использовать.

Во всех предыдущих примерах определение main() содержало пустой список:

int main() { ... }

Развернутая сигнатура main() позволяет получить доступ к параметрам, которые были заданы пользователем в командной строке:

int main( int argc, char *argv[] ){...}

argc содержит их количество, а argv – C-строки, представляющие собой отдельные значения (в командной строке они разделяются пробелами). Скажем, при запуске команды

prog -d -o ofile data0

argc получает значение 5, а argv включает следующие строки:

argv[ 0 ] = "prog"; argv[ 1 ] = "-d"; argv[ 2 ] = "-o"; argv[ 3 ] = "ofile"; argv[ 4 ] = "dataO";

В argv[0] всегда входит имя команды (программы). Элементы с индексами от 1 до argc-1 служат параметрами.

Посмотрим, как можно извлечь и использовать значения, помещенные в argv. Пусть

prog [-d] [-h] [-v]

[-o output_file] [-l limit_value]

file_name

программа из нашего примера вызывается таким образом:

[ file_name [file_name [ ... ]]]

Параметры в квадратных скобках являются необязательными. Вот, например, запуск программы с их минимальным количеством – одним лишь именем файла:

prog chap1.doc

prog -l 1024 -o chap1-2.out chapl.doc chap2.doc

prog d chap3.doc

Но можно запускать и так: prog -l 512 -d chap4.doc

При разборе параметров командной строки выполняются следующие основные шаги:

1.По очереди извлечь каждый параметр из argv. Мы используем для этого цикл for с

for ( int ix = 1; ix < argc; ++ix )

{

char *pchar = argv[ ix ];

//...

начальным индексом 1 (пропуская, таким образом, имя программы):

}

1.Определить тип параметра. Если строка начинается с дефиса (-), это одна из опций { h, d, v, l, o}. В противном случае это может быть либо значение, ассоциированное с опцией (максимальный размер для -l, имя выходного файла для -o), либо имя входного файла. Чтобы определить, начинается ли строка с дефиса, используем

switch ( pchar[ 0 ] ) { case '-': {

//-h, -d, -v, -l, -o

}

default: {

// обработаем максимальный размер для опции -1

//

имя выходного файла для

-

 

o

 

//имена входных файлов ...

}

инструкцию switch:

}

Реализуем обработку двух случаев пункта 2.

Если строка начинается с дефиса, мы используем switch по следующему символу для

case '-': {

switch( pchar[ 1 ] )

{

case 'd':

// обработка опции debug break;

case 'v':

// обработка опции version break;

case 'h':

// обработка опции help break;

case 'o':

// приготовимся обработать выходной файл break;

case 'l':

// приготовимся обработать макс.размер break;

default:

//неопознанная опция:

//сообщить об ошибке и завершить выполнение

}

определения конкретной опции. Вот общая схема этой части программы:

}

Опция -d задает необходимость отладки. Ее обработка заключается в присваивании переменной с объявлением

bool debug_on = false;

case 'd': debug_on =

true;

значения true: break;

if

( d ebu g_o

n)

Внашу программу может входить код следующего вида: display_state_elements( obj );

case 'v':

cout << program_name << "::"

<<program_version << endl;

Опция -v выводит номер версии программы и завершает исполнение: return 0;

Опция -h запрашивает информацию о синтаксисе запуска и завершает исполнение.

case 'h':

// break не нужен: usage() вызывает exit()

Вывод сообщения и выход из программы выполняется функцией usage(): usage();

Опция -o сигнализирует о том, что следующая строка содержит имя выходного файла. Аналогично опция -l говорит, что за ней указан максимальный размер. Как нам обработать эти ситуации?

Если в строке параметра нет дефиса, возможны три варианта: параметр содержит имя выходного файла, максимальный размер или имя входного файла. Чтобы различать эти случаи, присвоим true переменным, отражающим внутреннее состояние:

//если ofi1e_on==true,

//следующий параметр - имя выходного

файла

bool ofi1e_on = false;

//если ofi1e_on==true,

//следующий параметр - максимальный размер

bool limit_on = false;

case 'l': limit_on =

true;

break;

case 'o': ofile_on =

true;

Вот обработка опций -l и -o в нашей инструкции switch: break;

Встретив строку, не начинающуюся с дефиса, мы с помощью переменных состояния

// обработаем максимальный размер для

опции -1

//

имя выходного файла для

-o

//

имена входных файлов ...

default: {

 

 

// ofile_on включена, если -o встречалась if ( ofile_on ) {

//обработаем имя выходного файла

//выключим ofile_on

}

else if ( limit_on ) { // если -l встречалась

//обработаем максимальный размер

//выключим limit_on

}else {

//обработаем имя входного файла

можем узнать ее содержание:

}

Если аргумент является именем выходного файла, сохраним это имя и выключим

if ( ofile_on ) { ofile_on =

false; ofile = pchar;

ofile_on:

}

Если аргумент задает максимальный размер, мы должны преобразовать строку встроенного типа в представляемое ею число. Сделаем это с помощью стандартной функции atoi(), которая принимает строку в качестве аргумента и возвращает int (также существует функция atof(), возвращающая double). Для использования atoi() включим заголовочный файл ctype.h. Нужно проверить, что значение максимального

// int limit; else

if ( limit_on ) { limit_on = false; limit = atoi( pchar ); if ( limit < 0 ) {

cerr << program_name << "::"

<<program_version << " : error: "

<<"negative value for limit.\n\n";

usage( -2 );

}

размера неотрицательно и выключить limit_on:

}

Если обе переменных состояния равны false, у нас есть имя входного файла. Сохраним

его в векторе строк:

file_names.push_back( string( pchar ));

При обработке параметров командной строки важен способ реакции на неверные опции. Мы решили, что задание отрицательной величины в качестве максимального размера будет фатальной ошибкой. Это приемлемо или нет в зависимости от ситуации. Также можно распознать эту ситуацию как ошибочную, выдать предупреждение и использовать ноль или какое-либо другое значение по умолчанию.

Слабость нашей реализации становится понятной, если пользователь небрежно относится к пробелам, разделяющим параметры. Скажем, ни одна из следующих двух

prog - d

dat aOl

строк не будет обработана: prog -oout_file dataOl

(Оба случая мы оставим для упражнений в конце раздела.)

Вот полный текст нашей программы. (Мы добавили инструкции печати для трассировки выполнения.)

#include <iostream>

#include <string> #include <vector>

#include <ctype.h>

const char *const program_name = "comline";

const char *const program_version = "version 0.01 (08/07/97)";

inline void usage( int exit_value = 0 )

{

//печатает отформатированное сообщение о порядке вызова

//и завершает программу с кодом exit_value ...

cerr << "порядок вызова:\n"

<<program_name << " "

<<"[-d] [-h] [-v] \n\t"

<<"[-o output_file] [-l limit] \n\t"

<<"file_name\n\t[file_name [file_name [ ... ]]]\n\n"

<<"где [] указывает на необязательность опции:\n\n\t"

<<"-h: справка.\n\t\t"

<<"печать этого сообщения и выход\n\n\t"

<<"-v: версия.\n\t\t"

<<"печать информации о версии программы и выход\n\n\t"

<<"-d: отладка.\n\t\t включает отладочную печать\n\n\t"

<<"-l limit\n\t\t"

<<"limit должен быть неотрицательным целым числом\n\n\t"

<<"-o ofile\n\t\t"

<<"файл, в который выводится результат\n\t\t"

<<"по умолчанию результат записывается на стандартный

вывод\n\n"

<<"file_name\n\t\t"

<<"имя подлежащего обработке файла\n\t\t"

<<"должно быть задано хотя бы одно имя --\n\t\t"

<<"но максимальное число не ограничено\n\n"

<<"примеры:\n\t\t"

<<"$command chapter7.doc\n\t\t"

<<"$command -d -l 1024 -o test_7_8 "

<<"chapter7.doc chapter8.doc\n\n";

exit( exit_value );

}

int main( int argc, char* argv[] )

{

bool debug_on = false; bool ofile_on = false; bool limit_on = false; int limit = -1; string ofile;

vector<string> file_names;

cout << "демонстрация обработки параметров в командной строке:\n" << "argc: " << argc << endl;

for ( int ix = 1; ix < argc; ++ix )

{

cout << "argv[ " << ix << " ]: " << argv[ ix ] << endl;

char *pchar = argv[ ix ]; switch ( pchar[ 0 ] )

{

case '-':

{

cout << "встретился \'-\'\n"; switch( pchar[ 1 ] )

{

case 'd':

cout << "встретилась -d: "

<< "отладочная печать включена\n";

debug_on = true; break;

case 'v':

cout << "встретилась -v: "

<< "выводится информация о версии\n";