Цитата
Вопрос
Недавно я разработал консольное CLR-приложение в Visual Studio® 2005. Я заметил, что приложение Visual Studio создало главную функцию, которая выглядит так:
int main(array<System::String ^> ^args)
{
...
return 0;
}
Кажется, это отличается от старых argc/argv, которые я знаю в C/C++. Когда я попытался получить доступ к args[0], думая, что это будет имя файла (как в C/C++), я обнаружил, что args[0] является не именем файла, а первым параметром командной строки. А что произошло с именем файла? И не могли бы вы объяснить причину такого изменения?
Джейсон Лэндрю
Ответ
Да, в современном мире все быстро меняется. И все уже не так как прежде, да? Мы жили с функцией argc/argv с 1972 года, когда был разработан язык C, а теперь программисты из Редмонда это изменили. Возможно, они хотели, чтобы все как следует выучили новый синтаксис массивов.
Одной из причин для перехода на новый синтаксис является необходимость компилировать программу с ключом /clr:safe, что является предельным уровнем безопасности кода. Это как будто вы запираете свою программу в "чистую" комнату, типа тех стерильных помещений с хромированной мебелью, куда все входят через шлюз и без шапок и обуви. Если задан ключ /clr:safe, компилятор налагает все возможные ограничения. Нельзя использовать машинные (native) типы. Нельзя использовать глобальные переменные. Нельзя вызывать неуправляемые функции. Короче говоря, вы не можете использовать многие преимущества. И почему же вы подвергли себя таким ограничениям? Чтобы быть по-настоящему уверенным, что ваш код является безопасным. Говоря техническим языком, режим /clr:safe генерирует «проверяемый» код, что означает, что CLR может проверить, что ваш код не нарушает настроек безопасности, например, не старается получить доступ к файлу, когда настройки безопасности для пользователя этого не разрешают. Одними из членов длинного списка запретов для /clr:safe являютсяnative указатели — или просто, указатели. (Слово «native» является здесь избыточным, поскольку не может быть указателя на управляемый тип). Так как указатели в режиме /clr:safe запрещены, старая декларация argv просто не работает. Поэтому разработчики из Редмонда изменили декларацию и используют массив String^. А так как массивы знают свою длину, нет необходимости в argc. Стартовый код для создания и инициализации массива arg, который вызывается перед тем, как передать управление в вашу главную функцию, содержится в runtime-библиотеке. Если использовать /clr:safe не планируется, всегда используйте в главной функции можно использовать старый список параметров argc/argv.
Это объясняет причину использования управляемого массива, но остается вопрос с args[0]: почему он является первым параметром команды, а не именем файла? Я не могу говорить за программистов Microsoft, но возможно, они подумали, что имеет смысл опустить имя файла, может быть потому, что оно вам не нужно. В любом случае, это не имеет большого значения, так как получить имя файла легко. Я уверен, что есть много способов сделать это, но самым явным и ориентированным на CLR (совместимым с /clr:safe) способом, я думаю, является использование класса System::Environment. В нем имеется следующий метод:
static array<String^>^ GetCommandLineArgs ()
В отличие от параметра args, передаваемого в main, массив, возвращаемый из Environment::GetCommandLineArgs, на самом деле начинается с имени исполняемого файла.
И, наконец, зачем может понадобиться узнать имя собственного EXE-файла? Ведь это вы пишете программу, и предполагается, что вы знаете, как она называется. Одной из причин для этого может быть генерация сообщения системы справки, в котором содержится имя программы, без необходимости заносить это имя в код. Справочное сообщение может выглядеть так:
FooFile -- Turns every word in your file to "foo"
usage:
FooFile [/n:<number>] filespec
filespec = the files you want to change
<number> = change only the first <number> occurrences
Здесь FooFile является именем программы. Я бы мог просто написать «FooFile» в тексте сообщения, но я давно уже знаю, что часто переименовываю программы или копирую код из одной программы в другую. Если же имя программы будет получено в самой программе (через argv или Environment::GetCommandLineArgs), то в справочном сообщении всегда будет правильное имя, даже если я переименую файл или скопирую код в другую программу.
Счастливого вам программирования!