Я работал над примером в книге K&R C, где вас просят создать калькулятор RPN, который принимает ввод через аргументы командной строки. Мое решение, по сути, перебирает указанные аргументы и выдает ответ, но я кое-что заметил:

Если бы я дал символ умножения (звездочку) '*' без одинарных кавычек, gcc предполагает, что это ввод с подстановочным знаком, поэтому мой ввод

$./rpn 5 10 *

Дает мне результат

read 5
read 10
read rpn
read rpn.c
= 0

Заключение звездочки в одинарные кавычки решает проблему.

$./rpn 5 10 '*'
read 5
read 10
read *
= 50

Мой вопрос: есть ли способ очистить ввод, чтобы моя программа не требовала, чтобы звездочка была заключена в одинарные кавычки, или это поведение вызвано чем-то более фундаментальным (например, двоичное выполнение Linux / POSIX / UNIX и обработка аргументов)?

9
MSalmo 24 Ноя 2014 в 08:50
1
Все, что связано с оболочкой; ничего общего с компилятором C вообще. Для демонстрации попробуйте написать маленькую программу: #include <unistd.h> и int main(void) { char *args[] = { "./rpn", "5", "10", "*", 0 }; execv(args[0], args); return -1; }. Оболочка обычно расширяет *; это позволяет избежать использования оболочки, поэтому расширения не происходит.
 – 
Jonathan Leffler
24 Ноя 2014 в 09:04
2
GCC ничего не знает. Оболочка — это та, которая подает входные данные в вашу программу.
 – 
Ryan
24 Ноя 2014 в 09:05
@self Я пробовал это, и это так, как вы сказали; он выполняется и выводит правильный ответ. Как указано ниже @IgnacioVazquez-Abrar, это вызвано тем, что bash расширяет подстановочный знак * в список всех файлов в текущем каталоге. Я, безусловно, должен быть более внимательным к оболочке.
 – 
MSalmo
24 Ноя 2014 в 09:25
1
Это стандартная ловушка; * — единственный широко используемый арифметический оператор, который также является метасимволом оболочки. Если вы использовали круглые скобки с инфиксным калькулятором (по определению вы не используете круглые скобки с калькулятором RPN), то они тоже будут вам мешать, поскольку они также имеют особое значение для оболочки.
 – 
Jonathan Leffler
24 Ноя 2014 в 09:28
Если вы действительно хотите, чтобы ваш Bash не выполнял расширение пути, начните его с bash -f или введите set -f в запущенном Bash (и set +f для отмены).
 – 
mafso
24 Ноя 2014 в 14:28

2 ответа

Лучший ответ

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

8
Ignacio Vazquez-Abrams 24 Ноя 2014 в 08:58
Я понимаю. Это может быть очень распространенной причиной неопределенного поведения, если кто-то не слишком осторожен с тем, какие входные данные программирует разработчик, если они не принимают во внимание оболочку. Я предполагаю, что в этом примере есть скрытый урок, и это связано с этим часто упускаемым из виду уровнем исполнения.
 – 
MSalmo
24 Ноя 2014 в 09:08
1
На мой взгляд, это не совсем упущено из виду. Вы просто должны знать свои инструменты.
 – 
Ryan
24 Ноя 2014 в 09:09
И это не «неопределенное поведение». Это прекрасно определено; это просто не то, что вы хотите здесь.
 – 
user149341
24 Ноя 2014 в 09:28
Ты прав. Думаю, лучше использовать слово «непреднамеренный».
 – 
MSalmo
24 Ноя 2014 в 09:30

Введите данные как

$./rpn "5 10 *" 

Все аргументы в "" и в программе вы получите все аргументы в argv[1], затем проанализируйте эту строку, разделив ее пробелом.

Таким образом, вам нужно обрабатывать любые подстановочные знаки / специальные символы особым образом.

0
Jeegar Patel 24 Ноя 2014 в 09:01
В качестве альтернативы вы рассматриваете все символы как требующие особого внимания… и усложняете программу rpn.
 – 
Jonathan Leffler
24 Ноя 2014 в 09:07
Когда когда-либо появляется какое-либо пространство в любых именах файлов / пути, которые задаются таким аргументом командной строки, это создает проблему в Linux и Windows, поэтому еще один способ справиться с такими всеми вещами - рассматривать все их как специальные
 – 
Jeegar Patel
24 Ноя 2014 в 09:09
@ Mr.32 Mr.32 Я бы обычно согласился с вами, если бы сценарий был другим, однако в упражнении специально требовалось, чтобы ввод обрабатывался как дискретные аргументы командной строки.
 – 
MSalmo
24 Ноя 2014 в 09:12