Анимация
JavaScript
|
Главная Библионтека Следующая строка - инкремент???????????/ , Николай Смирнов пишет; Вероятно то, что случилось с программой, очевидно для вас, но я потерял несколько дней на отладку большой программы, в которой допустил подобную ошибку. Я внес строку с комментарием, который заканчивался большим количеством вопросительных знаков, и случайно отпустил клавишу <Shift> раньше времени. В результате случайно получилась последовательность ??/, представляющая собой триграф, который в первой фазе оказался преобразован в символ \, а он в свою очередь во второй фазе обработки исходного текста аннулировал следующий за ним символ \п (Н. Смирнов, частное сообщение). П ослсдовате л ьн ость ??/ преобразуется в символ \, который, будучи последним символом в строке, представляет собой директиву стыковки строк! В нашем случае такой стыкуемой строкой оказалась строка с инструкцией ++х;, которая теперь оказалась частью комментария, так что инкремент в приведенной программе ни разу не выполняется. Интересно, что если вы посмотрите документацию по Gnu g++ в части, где говорится об опции командной строки -wtrigraphs, то встретите следующее некорректное обобщение; Предупреждение не выдается для триграфов в комментариях, поскольку они не влияют на смысл программок Это может быть вполне справедливо в подавляющем большинстве случаев, но вы только что познакомились с контрпримером -- из реальной программы! - когда приведенное утверждение оказывается неверным. 2. О скольких различных ошибках сообщит соответствующий стандарту компилятор при работе с приведенным исходным текстом? пример 32-2 struct X { static bool f( int* p ) { return p && 0[p] and not p[l:»p[2]; }; Краткий ответ: ноль. Этот код совершенно корректен и соответствует ставдарту (хочет ли того автор данного исходного текста или нет). Рассмотрим по порядку каждое из выражений, которые могут вызвать вопросы, и покажем, почему в действительности они корректны. • Выражение 0[р] совершенно корректно и имеет тот же смысл, что и выражение р[0]. В С (и С-И-) выражение вида х[у], где либо х. либо у имеет тип указателя, а другая величина представляет собой целочисленное значение, всегда означает *(х+у). В нашем случае 0[р] и р[0] имеют один и тот же смысл, поскольку означают *(0+р) и *(р+0) соответственно, что совершенно одинаково. Дополнительную информацию можно найти в [С99] §6.5.2.1. • and и not представляют собой корректные ключевые слова, представляющие собой альтернативную запись операторов && и ! соответственно. • :> представляет собой совершенно корректный дифаф си.мвола ], а не "смайлик". Этот диграф превращает последнюю часть выражения в простое неравенство р[1]>р[2]. Поиск в Google по запросу "trigraphs within comments" дает как этот, так и несколько других интересных и/или забавных трюков. • "Лишняя" точка с запятой после описания функции-члена разрешена и не привносит никаких неприятностей. Синтаксис определения класса С++ разрешает объявление пустых членов (одинокие точки с запятой) где угодно в пределах класса, так часто, как только вы пожелаете. Например, следующая строка - совершенно корректное определение класса без членов: class X { ;;;;;;;;;; }; Для большинства программистов наибольший сюрприз из представленных здесь преподносит диграф :>. Конечно, возможно, здесь вкралась опечатка и автор на самом деле имел в виду нечто иное, например, р[1]»р[2], но даже если это и опечатка, то исходный текст и с ней (в таком случае - к сожалению) остается соверщенно корректным. Задача 33. Ооооператоры Сложность: 4 Сколько операторов можно поместить подряд так, чтобы это имело смысл? В определенном смысле эту задачу можно считать шуткой. Вопрос для новичка 1. Какое наибольшее количество плюсов (+) могут быть расположены подряд, без включения пробельных символов, в корректной программе на С++? Примечание: конечно, плюсы в комментариях, директивах препроцессора, макросах и литералах не учитываются. Это было бы неспортивно. Вопрос для профессионала 2. Аналогично, чему равно наибольшее количество каждых из приведенных далее символов, которые могут располагаться в программе подряд, без вставки пробельных символов, вне комментариев в корректной программе на С++? а) & б) < в) I Например, для пункта а) код if(a&&b) демонстрирует тривиальный случай двух п осл с до вате л ь н ы х символов & в корректной программе на С++. Попробуйте найти примеры с большим количеством символов. Решение Правило "максимального глотка" Правило "максимального глотка" гласит, что при разбивке символов исходного текста на лексемы компилятор должен поступать в соответствии с жадным алгоритмом -- т.е. выбирать наиболее длинную из возможных лексем. Таким образом, » всегда интерпретируется как единая лексема - оператор извлечения из потока (или битового сдвига вправо), и никогда - как две отдельные лексемы >, даже в ситуации наподобие следующей: tempi ate<cl ass т = x<Y» Вот почему такой код следует писать с дополнительным пробелом: tempiate<class т = x<Y> > Аналогично, »> всегда интерпретируется как » с последующим за ним >, но не как > с последующим ». Операторные шутки 1. Какое наибольшее количество плюсов (+) могут быть расположены подряд, без включения пробельных си.мволов, в корректной программе на С++? Примечание: конечно, плюсы в комментариях, директивах препроцессора, макросах и литералах не учитываются. Это было бы неспортивно. Можно создать исходный файл, содержащий последовательность символов + произвольной длины (ограниченной возможностями компилятора по обработке длинной строки). Если последовательность состоит из четного количества символов +. она интерпретируется как ++ ++++++ ... ++, т.е. как последовательность двухсимвольных 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 [ 63 ] 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |