Pull to refresh

Comments 26

А где здесь макросы, вы показали типичный метод с переменным числом параметров. В данном случае виден типичный обман :-)

Вообще от этого давно пора уходить на потоки.
Само собой в некотором смысле это обман, ведь макросов с переменным количеством аргументов не бывает.

Макрос тут:
// Собственно сам макрос
#define dbg DbgFuncRet(__FILE__, __LINE__)


Используется так:
int main ()
{
    // ....
    dbg ("Test %d, %s, %f\n", 100, "test-test", 99.99f);
}


dbg (...) будет развернуто в вызов
DbgFuncRet(__FILE__, __LINE__)("Test %d, %s, %f\n", 100, "test-test", 99.99f);

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

Причем здесь потоки я не понял.
Ну я это и имел ввиду, что макрос на самом деле не принимает параметры, а заворачивает метод, который в свою очередь возвращает функтор, я у себя же так делать не стал, ибо это довольно жуткий и устаревший подход. Я у себя использовал потоки и boost::format, который является безопасным, решения было принято для возможности локализации логов и соответственно нормальной обработки косяков в случае недобора или перебора параметров.
В С++ нет методов, есть функции-члены (классов). Возвращается не функтор, а указатель на функцию.
Автор в тексте указывает, что у него в проекте присутствуют файлы на чистом Си, поэтому ни о каких бустах речи быть не может.
Макросы с переменным числом параметров бывают. Я-то грешным делом подумал, что статья именно об этой методике.

Пример из написанной мной библиотеки Logger для журналирования в Qt-приложениях:
#define LOG_DEBUG(...)   Logger::write(Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)

...

class Logger
{
    ...
    static void write(LogLevel logLevel, const char* file, int line, const char* function, const char* message);
    static QDebug write(LogLevel logLevel, const char* file, int line, const char* function);
    ...
}


Используется это примерно так:
LOG_DEBUG("Message 1");
LOG_DEBUG() << "Message 2" << "ok";


Собственно, использования Variadic Macros описано в статье в англоязычной Википедии :)
Как это макросов с переменным числом аргументов не бывает?

#if defined(__GNUC__) || defined(__GCCE__)
#define DLOG(x, args...) (isNiocoreLogEnabled? DOutDebugMessage(x, args): ((void)0))
#else
#define DLOG(x, ...) (isNiocoreLogEnabled? DOutDebugMessage(x, __VA_ARGS__): ((void)0))
#endif
Добавьте развернутый пример использования, чтобы у людей меньше вопросов было.
Я даже представить не могу, что еще нужно добавлять?
Со мной, наверное, что-то не так, но я даже свёрнутого примера не вижу.
что-то я не понял, зачем так делать, если, например, в gcc есть все нужное:
// debug mode, -DEBUG
#ifdef EBUG
	#define RED			"\033[1;32;41m"
	#define GREEN		"\033[5;30;42m"
	#define OLDCOLOR	"\033[0;0;0m"
	#define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__)
	#define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \
					fprintf(stderr, __VA_ARGS__);			\
					fprintf(stderr, "\n");} while(0)
#else
	#define FNAME()	 do{}while(0)
	#define DBG(...) do{}while(0)
#endif //EBUG


А еще можно даже без gettext'а на макросах сделать «велосипедную» псевдолокализацию:
// locale.h
#define		_LANG(_var, _ru, _en)	char _var##ru[] = _ru;\
					char _var##en[] = _en;\
					char *_var[2] = {_var##ru,  _var##en};
#define		_L(x)	(x[Lang])
unsigned char Lang = 1; // по умолчанию - английский, меняем на русский, если LC_MESSAGES==ru или HTTP_ACCEPT_LANGUAGE==ru
_LANG(_s_Name_, "Ваше имя", "Your name");
…

// file.c
printf("%s:<input ... >\n", _L(_s_Name_));


И вообще, конечно, макросы — штука занятная.
а нужно было написать всего 3 строки:

#define QUOTE_(WHAT) #WHAT
#define QUOTE(WHAT) QUOTE_(WHAT)
#define dbg(format, ...) printf("%s: "format, __FILE__":"QUOTE(__LINE__), ## __VA_ARGS__)

Вот всегда так на Хабре — мучаешься, думаешь, пишешь 2 дня статью, а оказывается что всё можно сделать в 3 строки. Автору — обидно, читателю — профит.
Спасибо.
Ну, любому автору, перед тем как писать статью на хабр (да и не только) о новоизобретенном велосипеде, имеет смысл чутка погуглить, не переоткрывает ли он Америку. В частности, если собираешься писать о «расширении» функционала языка, стоит серьезно поисследовать, точно ли такого функционала нет в наличии по умолчанию :-)
Там же описан костыль для говнокомпилятора
Давно не использовал С, подскажите, зачем два макроса QUOTE() и QUOTE_(), почему нельзя одним обойтись?
QUOTE(__LINE__) --> QUOTE_(23) --> "23"
Если бы дополнительного макроса не было, то результат был бы "__LINE__"
опять любители комментировать, а не читать. там же прямо написано «нашел такое решение, но у меня VC6». Да и упоминавшийся StdAfx.h мог бы навести на мысли…

А переменное число параметров чистым препроцессором можно сделать так:

#define dbg(X)  do { printf X; printf("File: %s:%s\n" __FILE__, __LINE__); } while(0)


вся штука в том, что вызывать это нужно будет так:

dbg(("debugging is %s", debug? "on" : "off"))


то есть, по две пары скобок писать
Можно так сделать:

#ifdef DEBUG
#define dbg    printf("%s:%d", __FILE__, __LINE__), printf
#else
#define dbg    (void)
#endif
Можно. Только зачем выводить данные в консоль если нужно в файл?
Воспользуйтесь фантазией для замены printf на my_printf_to_file
Зачем писать две пары скобок, если можно одну?
И вообще почему VS6? Это какое-то принципиальное требование?
Да. У того же PHP расширения нужно собирать тем компилятором, каким собран основной модуль.
Only those users with full accounts are able to leave comments. Log in, please.