2014-11-24 26 views
7

Pracowałem nad przykładem w książce K R K &, w której prosi się o zbudowanie kalkulatora RPN, który pobiera dane wejściowe za pośrednictwem argumentów wiersza poleceń. Moje rozwiązanie zasadniczo iteruje za pośrednictwem podanych argumentów i wypluwa odpowiedź, ale zauważyłem coś:argv: dezynfekcja symboli wieloznacznych

Jeśli miałbym podać znak mnożenia (gwiazdkę) '*' bez pojedynczych cudzysłowów, gcc zakłada, że ​​jest to znak wieloznaczny, więc mój wkład

$./rpn 5 10 * 

daje mi moc

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

owijania gwiazdkę z apostrofami środków zaradczych emisji

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

Moje pytanie brzmi: czy istnieje sposób na dezynfekcję danych wejściowych, aby mój program nie wymagał oznaczania gwiazdką pojedynczych cudzysłowów, czy też jest to zachowanie spowodowane przez coś bardziej fundamentalnego (np. Wykonywanie binarne Linux i POSIX/UNIX i obsługa argumentów)?

+1

Cholernie dobre pytanie. – Qix

+1

Wszystko, co trzeba zrobić z powłoką; nie ma nic wspólnego z kompilatorem C. Aby zademonstrować, spróbuj napisać mały program: '#include ' i 'int main (void) {char * args [] = {" ./rpn "," 5 "," 10 "," * ", 0}; execv (args [0], args); return -1; } '. Powłoka zwykle rozszerza '*'; dzięki temu unika się używania powłoki, więc nie występuje ekspansja. –

+2

GCC nic nie wie. Powłoka jest tą, która zasila wejście do twojego programu. –

Odpowiedz

6

Powłoka rozszerza glob przed wykonaniem programu. Cytujesz glob nie z powodu GCC, ale z powodu powłoki. Jeśli nie chcesz tego zachowania, użyj powłoki, która nie honoruje globs.

+0

Rozumiem. Może to być bardzo częstą przyczyną nieokreślonego zachowania, jeśli nie jest się zbyt ostrożnym z tym, do czego wejścia programuje programista, jeśli nie uwzględniają powłoki. Przypuszczam, że w tym przykładzie jest ukryta lekcja, a to wyjaśnia tę często pomijaną warstwę wykonawczą. – MSalmo

+1

To naprawdę nie jest przeoczone, w mojej opinii. Musisz tylko znać swoje narzędzia. –

+0

I to nie jest "niezdefiniowane zachowanie". Jest doskonale zdefiniowany; po prostu tego nie chcesz. – duskwuff

0

wejście dać jako

$./rpn "5 10 *" 

Wszystko argumentem "" i programem dostaniesz wszystkie argumenty pod argv[1] następnie analizować ten ciąg przez wydzielenie przestrzeni.

W ten sposób musisz obsługiwać dowolne znaki wieloznaczne/specjalne w specjalny sposób.

+0

Alternatywnie traktujesz wszystkie postacie jako wymagające specjalnej uwagi ... i komplikując program 'rpn'. –

+0

Kiedykolwiek jakakolwiek przestrzeń pojawia się w nazwach plików/ścieżkach podanych przez takie argumenty, argumemt tworzy problem w systemach Linux i Windows, więc innym sposobem radzenia sobie z takimi wszystkimi rzeczami jest traktowanie ich jako specjalnych –

+0

@ Mr.32 Zwykle zgadzam się z tobą, jeśli scenariusz był inny, jednak ćwiczenie wymagało przetworzenia danych wejściowych jako dyskretnych argumentów wiersza poleceń. – MSalmo