Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 августа!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Программисты долго мучаются с кодом прогаммы, изучают С++, WinAPI функции, MSDN. Потом пишут банальную систему защиты или навешивают банальный протектор, а крэкеры и реверсеры справляются с такой защитой за 5 минут. В итоге, продажи программы почти нулевые. Чтобы такого не допустить, тут самому надо немного поднабрать опыта отладки, реверсинга, тот же отладчик Ollydbg изучить или дизассемблер IDA Pro. Но где искать по крохам эти знания? Нет, конечно можно годами "методом тыка" разбираться, но куда быстрее видеокурс специальный посмотреть. Вот тут он есть: ссылка. Автор курса с большим опытом и объясняет понятно, я из этого курса много узнал про то как работает компьютер, процессор, про инструменты специальные и как с ними работать. Мои коллеги программисты на работе ничего такого и не знают, теперь я им нос утру.

Макроопределения и их недостатки.



Использовать макроопределения иногда удобно. Во многих случаях, конечно, стоит предпочесть использование параметризованных функций (шаблонов) и других механизмов, обеспечивающих проверку типов. Но использование препроцессора и макросов также имеет свою сферу применения.
Например, функции отладки и трассировки. Согласитесь, что это довольно удобно:
#ifdef USE_MY_TRACE
#define TRACE(a) CallTrace(a)
#else
#define TRACE(a) ((void)0)
#endif

Если USE_MY_TRACE не определено, вызовы CallTrace просто будут исключены на уровне препроцессора, а оптимизация при компоновке просто не включит нигде теперь не используемую функцию CallTrace в конечный исполняемый код программы. Удобно, но...
Обратим внимание на семейство макросов TRACE0, TRACE1, TRACE2, TRACE3, объявленных в MFC. Невозможность обойтись одним универсальным макросом объясняется следующими правилами синтаксиса:

1. При объявлении нескольких макросов с одинаковым именем препроцессор использует последнее определение и выводит предупреждения на этапе трансляции.

2. Следует из первого - в отличие от функций, макросы с одинаковыми именами, но различным числом или типом параметров, недопустимы.

3. Синтаксическая запись произвольного числа параметров (многоточие, '...') для макроопределений недопустима и является синтаксической ошибкой.


Умные макроопределения.

Оказывается, преодолеть названные выше недостатки макросов совершенно несложно. Сделать это можно при помощи простого трюка - использования класса, чем-то напоминающего так называемую идиому функторов. Это класс, для которого определен набор операторов "скобки". Итак, например, вот такой класс:
class MacroCall
{
public:

MacroCall()
{
}

void operator()(float val) const
{
printf("Float: %f\r\n", val);
}

void operator()(int val) const
{
printf("Integer: %d\r\n", val);
}

void operator() (const char *pszFmt, ...) const
{
if ( pszFmt == NULL || *pszFmt == 0 )
return;

va_list args;
va_start(args, pszFmt);

int size_msgbuf = _vscprintf(pszFmt, args) + 1;
char* msgbuf = new char[size_msgbuf];
vsprintf(msgbuf, pszFmt, args);

printf(msgbuf);

delete[] msgbuf;
va_end(args);
}
};
А теперь объявим макроопределение:
#ifdef USE_MACRO
#define MYMACRO MacroCall()
#else
#define MYMACRO __noop
#endif
И, наконец, пример использования:
MYMACRO("%s : %d\r\n", "Value", 10);
MYMACRO(55);
MYMACRO(3.1415926f);



Краткое обьяснение.

Всё очень просто. Строка вызова макроопределения
MYMACRO(55);
заменяется препроцессором на вызов
MacroCall()(55);
Т.е. вызываются конструктор и соответствующий «оператор скобки». Можно записать так:
MacroCall().operator()(55);

Заметим, что вызывается тот «оператор скобки», который соответствует типу и количеству аргументов – соответственно, для типов float и int разные при внешне одинаковом вызове одного и того же макроса:
MYMACRO(55); // вызван operator()(int val)
MYMACRO(3.1415926f); // вызван operator()(float val)
// operator() (const char *pszFmt, ...)
MYMACRO("%s : %d\r\n", "Value", 10);



Дополнительные замечания.

1. Обратим внимание на то, что в случае, если макрос MYMACRO не используется, он заменяется на __noop, специально введенный в компиляторе от Microsoft. Согласно документации, он позволяет компилятору правильно «проигнорировать» ненужный теперь список аргументов вызова при произвольном числе аргументов.
Однако если компилятор не поддерживает __noop или нечто аналогичное, можно просто определять неиспользуемый макрос как «пустой» или как ((void)0):

#define MYMACRO
или
#define MYMACRO ((void)0)


2. Сам вызов конструктора тоже может быть использован для дополнительных аргументов. Например:
class MacroCallLine
{
public:

MacroCallLine(int L) : line_num(L)
{
}

void operator()(const char* msg) const
{
printf("Line: %d Message: %s\r\n", line_num, msg);
}

protected:
int line_num;
};

Теперь определим макрос:
#define TRACEMSG MacroCallLine(__LINE__)

Макрос теперь автоматически получает номер строки вызова.
И если его использовать где-нибудь в программе:
TRACEMSG("My message");
то мы получим что-то вроде следующего:
Line: 10 Message: My message

Замечу, что кроме __LINE__, определены также
__DATE__, __FILE__ и многое другое, и что особенно ценно на мой взгляд, __FUNCTION__. Замечу, что __FUNCTION__ работает удивительно корректно, возвращая имя класса и имя метода, разделенных '::'. Причем всё вышеназванное работает и для release версии, открывая прекрасные возможности для трассировки и доводки.


И напоследок.

1. Еще раз хочу обратить внимание: объявление макроса – это вызов конструктора, возможно с параметрами. Сам макрос не предполагает передачу аргументов. Например, был объявлен макрос в виде:
#define MYMACRO MacroCall()

Если объявить в следующей форме:
#define MYMACRO(p) MacroCall(p) // ЭТО УЖЕ ДРУГОЙ ВЫЗОВ

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

2. В классе MacroCall показан пример использования произвольного числа аргументов и форматирования при помощи vsprintf. Подробно обьяснять этот фрагмент я не буду, поскольку эти функции подробно описаны в MSDN.




<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS