Chinaunix

标题: 请问如何将指定字符串动态定义为宏 [打印本页]

作者: xhx321    时间: 2016-04-15 12:21
标题: 请问如何将指定字符串动态定义为宏
本帖最后由 xhx321 于 2016-04-18 12:17 编辑


貌似原来的描述把问题写的很乱, 也没表述清楚需求及重点。在这里重新写一下:
需要实现一个宏定义:O_PRINT_NAME_REGISTER(DEBUG_STRING_NAME)
例如:

************ 1.C ***********
O_PRINT_NAME_REGISTER(NET_TRACE)
O_PRINT_NAME_REGISTER(MAIN_TRACE)

void example(void)
{
     NET_TRACE(" net log");  // LINE 20
     MAIN_TRACE(" main log") // LINE 21
}

******* output *******
example - 20: net log
example - 21: main log

请注意需要能正确显示调用的行号和函数名。
请问如何实现上面这个宏 O_PRINT_NAME_REGISTER ?
作者: cokeboL    时间: 2016-04-15 14:11
只看标题的话我想说:你都动态了还扯什么宏

瞄了一眼需求我想说:那叫tag,你加个tag参数不就行了
作者: xhx321    时间: 2016-04-15 15:20
大神or牛人,表歪楼,如果认为很简单,请把后面实现了

#define O_PRINT_NAME_REGISTER(string, level ) ?

回复 2# cokeboL


   
作者: windoze    时间: 2016-04-15 15:56

  1. struct printer {
  2.     printer(int l) : level(l) {}
  3.     void operator()(const char *msg) const { if(level >= g_print_level) std::cout << msg << std::endl; }
  4.     const int level=0;
  5. };

  6. #define O_PRINT_NAME_REGISTER(name, level) const printer name(level)
复制代码
差不多是这么个东西?
作者: cokeboL    时间: 2016-04-15 16:17
我没歪楼,也没认为简单,我的意思是,不要对语法的追求过于妖魔化,单看为了实现几个打印函数的需求,很简单,你写个有几个参数的函数或者几个不同的函数
就搞定的事情,非要追求宏来生成,是不是有点舍本求末了?

码农最大的悲哀是该产品导向的场景,非要语言语法导向,费力不讨好,除了看上去语法牛逼不容易看懂,然并卵。
作者: cokeboL    时间: 2016-04-15 16:27
老是看见有人问奇葩的语法,普通点的正常点的写法都能实现,所以这种需求我总结就三种原因:
一是非要追求奇葩才显得逼格高
二是舍本求末没把用代码实现需求和用语法实现代码的重要性搞明白
三是想研究语法出于兴趣爱好
当然还有一种可能是上面这三种原因可能占不止一条

第三种值得鼓励,但是也别太迷恋了,其他情况,不鼓励
作者: cokeboL    时间: 2016-04-15 16:34
回复 4# windoze


    .c文件,没说支持c++哇。。
作者: windoze    时间: 2016-04-15 20:42
回复 7# cokeboL

我当然不可能给他一个C的,你知道我从来不代做作业。
作者: xhx321    时间: 2016-04-16 10:06
本帖最后由 xhx321 于 2016-04-16 11:21 编辑

谢谢版主的回复,因为是C++的写法,我不是特别懂。请问
在这种方案下,O_DEBUG其实是被转成的函数调用么?如果是函数调用,怎么解决行号打印的问题?
例如: 在code里是这样引用的
void main(void)
{
            O_DEBUG(" print level 0 for O_DEBUG");  // LINE 20
}
希望ouput时能打印出,O_DEBUG被引用的行号20:
        main - 20 : print level 0 for O_DEBUG

另外解释一下,我手上有一个和您类似的C方案, 但是暂时无法解决行号打印的问题,同时想看看有没有不用函数的方法,才跑到这提问题,不是想来抄作业的。

@cokeboL:
        1. 标题描述的“动态定义宏”,是对预编译,预处理而言的,动态与宏并不矛盾。
        2. 当别人提问时,如果解决不了就当学生好了,能不能别说别人不该做这个事情,然后瞎指导一通。个人认为这里是技术论坛,不需要来刷存在感。
        3. 我提这个问题是有自己的需求,不需要玩什么高深技术。


回复 8# windoze


   
作者: yulihua49    时间: 2016-04-18 10:17
本帖最后由 yulihua49 于 2016-04-18 10:25 编辑
xhx321 发表于 2016-04-15 12:21
想实现这样的功能。在一个.c里有多个管理打印的宏。例如:O_DEBUG, O_TRACE,O_ERROR,各自有其打印的级别l ...

你看这个行吗?


  1. int ShowLog(int DEBUG_level,const char *fmt,...);

  2. #define EMASS_LOG_DEBUG (5)
  3. #define EMASS_LOG_VERBOSE (4)
  4. #define EMASS_LOG_INFO (3)
  5. #define EMASS_LOG_WARN (2)
  6. #define EMASS_LOG_ERROR (1)

  7. #define EMAS_DEBUG(fmt, arg...) ShowLog(EMASS_LOG_DEBUG, "[D][T:%lx] %s(%d) "fmt, pthread_self(), __FILE__, __LINE__, ##arg)
  8. #define EMAS_VERBOSE(fmt, arg...) ShowLog(EMASS_LOG_VERBOSE, "[V][T:%lx] %s(%d) "fmt, pthread_self(), __FILE__, __LINE__, ##arg)
  9. #define EMAS_INFO(fmt, arg...) ShowLog(EMASS_LOG_INFO, "[I][T:%lx] %s(%d) "fmt, pthread_self(), __FILE__, __LINE__, ##arg)
  10. #define EMAS_WARN(fmt, arg...) ShowLog(EMASS_LOG_WARN, "[W][T:%lx] %s(%d) "fmt, pthread_self(), __FILE__, __LINE__, ##arg)
  11. #define EMAS_ERR(fmt, arg...) ShowLog(EMASS_LOG_ERROR, "[E][T:%lx] %s(%d) "fmt, pthread_self(), __FILE__, __LINE__, ##arg)
复制代码

作者: evaspring    时间: 2016-04-18 10:58
不是说宏里面的变量不能被展开么?
作者: xhx321    时间: 2016-04-18 12:19
多谢回复。
我之前的描述可能把你搞晕了。所以重新更新了一下问题。 谢谢!
回复 10# yulihua49


   
作者: yulihua49    时间: 2016-04-18 12:47
本帖最后由 yulihua49 于 2016-04-18 13:23 编辑
xhx321 发表于 2016-04-15 12:21
貌似原来的描述把问题写的很乱, 也没表述清楚需求及重点。在这里重新写一下:
需要实现一个宏定义:O_P ...

你这个方法是错误的,无法实现。
你还是看看我给你的例子,可以实现你的要求。函数名和文件名的用法一样,改成
__FUNCTION__
就可以了。tlog.c:

  1. #include <strproc.h>
  2. #include <log.h>

  3. int main(int argc,char *argv[])
  4. {
  5.         if(argc>1) envcfg(argv[1]);
  6.         EMAS_DEBUG("myname is %s",argv[0]);
  7.         EMAS_ERR("PID is %d",getpid());
  8.         return 0;
  9. }
复制代码
结果:

  1. 5  04/18 20:45'53 [D][T:7f7758e5d740] tlog.c(7) myname is ./tlog
  2. 1  04/18 20:45'53 [E][T:7f7758e5d740] tlog.c(8) PID is 26996
复制代码
系统时间设置的不对,这别管了,改成函数名也很简单。

是不是你要的结果?

给你改个带函数名的:
结果:

  1. 5  04/18 20:53'53 [D][T:7f0e8c42c740] tlog.c(7) main: myname is ./tlog
  2. 1  04/18 20:53'53 [E][T:7f0e8c42c740] tlog.c(8) main: PID is 29250
复制代码
log.h:


  1. #define EMAS_DEBUG(fmt, arg...) ShowLog(EMASS_LOG_DEBUG, "[D][T:%lx] %s(%d) %s: "fmt, pthread_self(), __FILE__, __LINE__, __FUNCTION__, ##arg)
  2. #define EMAS_VERBOSE(fmt, arg...) ShowLog(EMASS_LOG_VERBOSE, "[V][T:%lx] %s(%d) %s: "fmt, pthread_self(), __FILE__, __LINE__, __FUNCTION__, ##arg)
  3. #define EMAS_INFO(fmt, arg...) ShowLog(EMASS_LOG_INFO, "[I][T:%lx] %s(%d) %s: "fmt, pthread_self(), __FILE__, __LINE__, __FUNCTION__, ##arg)
  4. #define EMAS_WARN(fmt, arg...) ShowLog(EMASS_LOG_WARN, "[W][T:%lx] %s(%d) %s: "fmt, pthread_self(), __FILE__, __LINE__, __FUNCTION__, ##arg)
  5. #define EMAS_ERR(fmt, arg...) ShowLog(EMASS_LOG_ERROR, "[E][T:%lx] %s(%d) %s: "fmt, pthread_self(), __FILE__, __LINE__, __FUNCTION__, ##arg)
复制代码

作者: lwhjava    时间: 2016-04-19 22:13
回复 13# yulihua49


    这个宏定义很不错
作者: yulihua49    时间: 2016-04-20 12:50
lwhjava 发表于 2016-04-19 22:13
回复 13# yulihua49

我们采取一个日志函数+多个级别宏,而不采取多个函数的方式。
单个的函数还可以可变级别,就是级别可以是变量,有利于动态设置级别。
作者: cokeboL    时间: 2016-04-20 14:03
回复 15# yulihua49


    我是有Info Warn Error等几种函数,然后统一配置tag作为不同模块的标示,调试时候Info Warn Error里面看有没有配置相应的tag,配置了就输出,没配置的不输出,当然还分日志记录方式比如控制台或者文件

    加个tag之后想只调试某些模块可以很方便屏蔽其他模块的输出,看日志舒服些。不过像数据分析那样对日志做过滤也方便
作者: yulihua49    时间: 2016-04-21 11:47
本帖最后由 yulihua49 于 2016-04-21 11:59 编辑
cokeboL 发表于 2016-04-20 14:03
回复 15# yulihua49

我这个日志系统是可以加TAG的:
结果:

  1. 5 ./tlog:2930:  04/21 19:18'43 [D][T:7ff4fd92e740] tlog.c(9) main: myname is ./tlog
  2. 1 ./tlog:2930:  04/21 19:18'43 [E][T:7ff4fd92e740] tlog.c(10) main: PID is 2930
复制代码
程序:

  1. #include <strproc.h>
  2. #include <log.h>
  3. static char tag[100];
  4. int main(int argc,char *argv[])
  5. {
  6.         if(argc>1) envcfg(argv[1]);
  7.         sprintf(tag,"%s:%d: ",argv[0],getpid());
  8.         Showid=tag;
  9.         EMAS_DEBUG("myname is %s",argv[0]);
  10.         EMAS_ERR("PID is %d",getpid());
  11.         return 0;
  12. }
复制代码
还可以按线程分别TAG。

配置了TAG就用,不配置就没有TAG。
日志还是有的,显示级别和TAG两回事。

配置成3级,5级的就自动没有了:

  1. 5 ./tlog:2930:  04/21 19:18'43 [D][T:7ff4fd92e740] tlog.c(9) main: myname is ./tlog
  2. 1 ./tlog:2930:  04/21 19:18'43 [E][T:7ff4fd92e740] tlog.c(10) main: PID is 2930
  3. 1 ./tlog:3474:  04/21 19:26'21 [E][T:7f0a1c8a7740] tlog.c(10) main: PID is 3474
复制代码
前两行是5级的,后一行是3级的。
配置内容:

  1. LOGFILE=./LOG
  2. LOGLEVEL=3
复制代码

作者: cokeboL    时间: 2016-04-21 17:58
回复 17# yulihua49


    对对对,这样好用我的也是
作者: MMMIX    时间: 2016-04-22 22:25
cokeboL 发表于 2016-04-15 16:17
码农最大的悲哀是该产品导向的场景,非要语言语法导向,费力不讨好,除了看上去语法牛逼不容易看懂,然并卵。


你这就快走到另外一个极端了:技术无用论。
作者: cokeboL    时间: 2016-04-23 11:19
回复 19# MMMIX


不是的,我只是不纠结于语法,并不是反对钻研技术。

因为见过太多纠结于语法的cpper了,有哥们面试遇到语法党面试官,专问各种语言特性,然后压价,
不排除有项目就是需要这些,或者就是需要这种语法精通的人,但是绝大多数,都是不需要如此的搬砖
职位罢了。cpp的鄙视java的,java的鄙视c#的,而同是c++的又要通过语法、标准来形成鄙视链,对
技术的钻研是非常非常棒的事情,但现实中的情况是很大一部分人会因为自己对语言投入了太多精力而
过度迷恋语言本身,从而导致了鄙视链之类的事情,这样的态度对待编程语言我觉得对做事没有好处。。
作者: cokeboL    时间: 2016-04-23 11:23
回复 19# MMMIX


还有一些现象就是,3年5年c++,难精通,难积累到足够的内力或者习得框架、架构能力,同样努力
的情况下,java或者其他语言,可能已经达到架构师的水平,虽然内力甚至cpper高些,但落实到做产
品的能力上却不如java或其他语言的

所以我不是说技术无用,技术选型,可供选择的方案太多,技术路线也是,没有必要拘泥于单一语言




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2