2015-09-17 5 views
3

В source-code for nanodns, есть нетипичное использование троичного оператора в попытке уменьшить размер кода:Тернарный оператор как команда?

/* If the incoming packet has an AR record (such as in an EDNS request), 
* mark the reply as "NOT IMPLEMENTED"; using a?b:c form to save one byte*/ 
q[11]?q[3]|=4:1; 

Это не очевидно, что делает эта строка. На первый взгляд, похоже, что он присваивает значение одному из двух элементов массива, но это не так. Скорее, это похоже на элемент массива, или же ничего не делает (выполняется «команда» 1).

Похоже, она должна быть заменой для этой строки кода (который на самом деле один байт больше):

if(q[11])q[3]|=4; 

Буквальный эквивалент будет следующим образом:

if (q[11]) 
    q[3]|=4; 
else 
    1; 

Тернарный оператор обычно используется как часть выражения, поэтому просмотр его как отдельной команды кажется странным. В сочетании с кажущимся неуместным 1 эта линия почти квалифицируется как обфускационный код.

Я сделал быстрый тест и смог скомпилировать и запустить программу C (++) с константами данных в качестве «команды», например, void main() {0; 'a'; "foobar"; false;}. Это seems to bea sort of nop command, но я не могу найти информацию об этом использовании -Google isn’tvery amenableto thistype ofsearchquery).

Может ли кто-нибудь объяснить, что это такое и как он работает?

+1

'q [11]', а не 'q [1]'. Ваш анализ правильный; без большего контекста, это эквивалентно 'if (q [11]) {q [3] | = 4; } ', только короче. – Amadan

+0

Это эквивалентно 'if (q [11]) q [3] | = 4;' –

+0

* «эта строка почти квалифицируется как обфусканный код» * - действительно – 5gon12eder

ответ

2

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

«Это обычная практика в маленьких программах C, чтобы определить повторно использовать выражение , чтобы сделать код меньше»

завершено б *** S ***. Это утверждение - то, где вещи начали идти ужасно неправильно.

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

Если вы не программируете на компьютере 8086 с середины 80-х годов с очень ограниченным пространством на жестком диске, вам никогда не нужно «уменьшать размер кода». Вместо этого напишите читаемый код.

Это, как говорится, так как q представляет собой массив символов, код, который вы связаны эквивалентно

if(q[11]) 
{ 
    (int)(q[3] |= 4); 
} 
else 
{ 
    1; 
} 

Где 1 это заявление без побочного эффекта, он получит оптимизировано прочь. Он был установлен только там, потому что оператор ?: требует третьего оператора.

Единственная разница между операторами if и оператором ?: является тонкой: ?: неявно балансирует тип между вторым и третьим операндами.

Чтобы повысить читаемость и производить самостоятельно документирования кода, код должен получить переписать что-то вроде

if (q[AR_INDEX] != 0) 
{ 
    q[REPLY_INDEX] |= NOT_IMPLEMENTED; 
} 

Как примечание стороны, есть ошибка здесь: q[2]|=128;. q имеет тип char, который имеет определенную реализацию подпись, поэтому эта строка потенциально катастрофична. Основная проблема заключается в том, что вы никогда не должны использовать тип char для бит-мерных операций или любой арифметики, которая является классической ошибкой начинающего. Он должен быть заменен на uint8_t или unsigned char.

+1

Особо иронично, что если автор кода настолько обеспокоен размером исходного кода, что они решили использовать обфускацию формы инструкции для сохранения одного байта, то они добавляют «использование формы? B: c для сохранения одного байта» в комментарии - эти 33 байта, вероятно, уничтожают все, что скрывается от неясного кода! – TripeHound

+0

@TripeHound, то есть расширенная, объясненная версия кода. [[Minified] version] (http://maradns.blogspot.ca/2010/08/nanodns-updated.html) не содержит комментариев (кроме факультативного в начале, объясняющего лицензию). – Synetech

+0

@ Lundin, этот конкретный код был предназначен только для минимального DNS-сервера. Их цель заключалась в [«minify»] (http://maradns.blogspot.ca/2010/08/nanodns-updated.html) [более полной версии] (http://samiam.org/software/microdns.html) , например, как кодовый гольф. Но хороший улов с ошибкой, и спасибо за объяснения. – Synetech

5

В C и C++ любое выражение можно сделать в заявлении, положив в конце ;.

Другим примером является то, что выражение x = 5 можно сделать в инструкции: x = 5;. Надеюсь, вы согласитесь, что это хорошая идея.

Было бы неудобно усложнять язык, чтобы попытаться «запретить» некоторые подмножества выражений, из-за которых последовали ;. Этот код не очень полезен, но он является законным.

+1

Не просто усложнить - куча функций станет почти непригодной, например 'printf' - вы можете представить себе запись' int outputted = printf (".. . ");' каждый раз? :) – Amadan

+0

'В C и C++ любое выражение может быть сделано в утверждение путем положения; в конце ». И, естественно, типы POD (« встроенные ») - все выражения ... это имеет смысл. Конечно, они не обязательно означают что-то правильно? Думаю, вам нужно знать эти детали для обфускации кода-гольфа. Я бы подумал, что объекты должны быть специально написаны для поддержки использования в качестве выражения, но, по-видимому, они этого не делают; это встроено. Я только что протестировал с помощью 'myclass''. Это почти напоминает мне языки более высокого уровня, такие как Python и Ruby с кодом типа 1.to_s'. – Synetech

Смежные вопросы