Об оформлении
кода программ можно спорить бесконечно,
одни пишут так, другие этак. Однако сегодня
мы поговорим о том, как оформлять код
неправильно, как намеренно сделать его
менее читаемым. По научному это называется
обфускацией, однако в данном случае это не
обфускация в прямом понимании, а лишь
действительно затруднение понимания. Так
или иначе некоторые приемы могут оказаться
достаточно действенными и полезными и в
простом кодинге, так что область их
применения я готов оставить на твое
усмотрение.
Прежде всего поговорим о простых вещах. Ну
например - внешний вид. Не надо делать
структурированные и хорошо выглядящие
программы, в них каждый за 5 минут
разберется и исправит все, убрав твое
авторство. Сделай свою программу похожей на
произведение ASCII арта и всем будет приятно -
изучающим код прежде всего. Дальше -
переменные. Не надо их называть логически,
nWeight или result сразу расскажет врагу о
работе твоей программы, используй
однобуквенные обозначения, причем
выработай свою схему, отличную от
общепринятой, ну прекрати наконец
использовать i для счетчика в цикле! Можешь
использовать несколько одинаково
называющихся переменных в разных участках
кода или присвоить одной переменной
несколько имен и осуществлять их
ротацию. В названии функций будь абстрактен
и оперируй общими словами типа stuff, everything, this
и т.д. Как я уже говорил можно
переопределять переменные внутри разных
участков кода, например какой будет
результат у следующей программы:
int с = 26, d = 1;
{
int с = 69;
d += с;
}
printf("%d\t%d\n", с, d);
Кто первый ответит получит 2 WMZ... 🙂 Можно
так же использовать слияние двух
переменных в одной простой операцией:
unsigned int с = 150, d = 931;
unsigned long long merge = 0;
merge = c << sizeof(c) + d;
Что получится в итоге? Переменная "с"
разместится в первых 32 битах, а "b" в
последних 32 битах 64-битной переменной "merge".
Этот метод можно расширить для целых 16-битных
чисел и 8-битных символов.
Перейдем к ходу выполнения программы.
Можно сказать, что понимание работы
программы в большей степени зависит от
понимания хода ее выполнения. Поэтому
особое внимание следует уделить обфускации
алгоритма. Например, ради экономии кода и
эффективности обращайте прямые циклы в
убывающие, вот так например:
for(i = 0; i < limit; i++)
{
(...)
}
в
int i = limit;
while(i--)
или
while(--i)
Ради приличия позаботьтесь так же о
развертывании возможных циклов. Например:
for(i = 0; i < 3; i++)
{
sum += inрut[i];
}
легко преобразовать в:
sum += input[0];
sum += input[1];
sum += input[2];
Или в более простую строчку:
sum += inрut[0] + input[1] + input[2];
Если цикл слишком велик для такого
раскладывания, можно сделать так:
for(i = 0; i < limit; i += 3) { sum += inрut[i]
+ inрut[i + 1] + inрut[i + 2]; }
Простой и эффективный способ запутать
читающего, согласитесь?
С функциями тоже можно поиграться, сведя
возможные из них к малопонятным строкам.
Например такую функцию
int foo(int a, int b)
{
a = а - b;
b++;
a = а * b;
return a;
}
гораздо эффективнее определить так:
#define foo(а, b) ((а - b++) * (а * b))
Без боязни внедряйте излишний код или
кодовые ловушки. Помните о различии = и == в С?
Наверняка, ну а кто с первого раза поймет
такой пример?
if(a = 2) b++;
Кто правильно скажет результат? А вот
такой пример?
b ^= b;
if(b) а = ++с;
Он никогда не выполнится, все ведь это
сразу поняли, не так ли?