与井号'#'相反的宏

lonelyrains 2011-06-16 07:10:35
看过http://topic.csdn.net/t/20020228/17/547920.html的问题,想到:
C++中有一种宏'#':可以把代码变成字符。
例如:
#define ToStr(s) #s
void main()
{
printf("%s",ToStr(1234));

int helloworld = 0;
printf("%s",ToStr(helloworld));
}

请问一下什么语言中有与此对应相反的宏:把字符变成代码?假设有且为@,可达到以下效果。
#define ToCode(s) @s
void main()
{
ToCode("int") a=0;//声明一种变量
}

如果目前没有任何语言有,那么如何用http://topic.csdn.net/t/20020228/17/547920.html 中的6楼提到的类似MFC的动态生成方法实现那么多宏的遍历和上述这个问题?
...全文
417 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 lonelyrains 的回复:]
其实这个问题的来源是我想写一个针对所有动态库中的函数的调用测试MFC工程。
比如动态库中有一个函数int add(int a,int b),用户只用在文本框中输入int add(int 3,int 4)和该函数所在的dll路径,点击运行,马上就可以输出返回值。
我所知的调用dll中函数的方式:先定义函数指针类型:typedef int (WINAPI ADD)(int a,int b);然后定义该指针类型的指针,赋值为LoadLibrary的返回值。问题是要针对动态库中所有的函数,就涉及到很多种数据类型和参数列表组合。如何针对复杂多变的函数,定义指针类型?
[/Quote]
如果只考虑基本类型,不管数组和函数指针那种纠结的声明形式,这个解释器还是好写的……

要是你非要照顾到所有可能的情况,只能祝你好运了……
w_anthony 2011-06-22
  • 打赏
  • 举报
回复
你这个要求如果要用C/C++实现,那就得自己写解释器,而解释器我估计你也写不出来(说实话别介意),所以最好的方法还是换脚本语言去实现这个功能。
lonelyrains 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 zhao4zhong1 的回复:]
#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
return 0;
}
……
[/Quote]
这两个宏的用法我也知道,但是还是不知道用来解决问题,请指点
赵4老师 2011-06-22
  • 打赏
  • 举报
回复
#与##在宏定义中的--宏展开
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
return 0;
}
宏展开时:
如果宏定义以#开头,不展开参数,直接替换。
故g(f(1,2))--->#f(1,2)--->"f(1,2)";
如果宏定义不以#开头,展开参数,直接替换,由外层向里层,如果碰到的是#开头的宏,不继续往里层展开,往外层展开。
由外层向里层,如果碰到的是以非#开头的宏,继续往里层走,直至最里层,开始一层层往外层展开。
故h(f(1,2))--->h(12)--->g(12)---->#12----->"12"。
PS:
##在宏中定义,是字符连接符
如a##b##c 等同于 "abc"
#在宏开头出现,是表示宏展开的方式不同
#a 等同于"a"
#abc 等同于 "abc"
复杂的:
#include <stdio.h>
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
int main()
{
char a = 'a';
cout<<g(a)<<endl; // a
cout<<g(g(a))<<endl; // a
printf("%s\n", h(f(1,2))); // 12
printf("%s\n", g(f(1,2))); // f(1,2)
printf("%s\n", g(h(f(1,2)))); // h(f(1,2))
printf("%s\n", h(g(f(1,2)))); // "f(1,2)"
printf("%s\n", h(h(f(1,2)))); // "12"
system("pause");
return 0;
}
预处理后的:(在编译选项中添加/EP /P后编译生成的.i文件)int main()
{
char a = 'a';
cout<<"a"<<endl;
cout<<"g(a)"<<endl;
printf("%s\n", "12");
printf("%s\n", "f(1,2)");
printf("%s\n", "h(f(1,2))");
printf("%s\n", "\"f(1,2)\"");
printf("%s\n", "\"12\"");
system("pause");
return 0;
}
---------------------------------------------------
宏解析
1. ##操作符
##操作符它的作用是在替代表中将其前后的参数连接成为一个预处理符号,它不能出现于宏替代表的开端和末尾。
例:
#define concat(s,t) s##t
#define AAA ABC
concat(A, AA)
将被替换成
ABC
2. 重新扫描和替换
在替换列表中的所有参数替换过之后,预处理器将对结果token序列重新扫描以便对其中的宏再次替换。
当正在替换的宏在其替换列表中发现自身时,就不再对其进行替换。今儿,在任何正在嵌套替换的宏的替换过程中遇到正被替换的宏就对其不再进行替换(防止递归)。
例:
#define ROOT AAA CCC
#define AAA ROOT
ROOT
将被替换成
ROOT CCC
赵4老师 2011-06-22
  • 打赏
  • 举报
回复
学习一下OleView.exe的用法。
lonelyrains 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 redleaves 的回复:]
C/C++ code

#include <stdio.h>
typedef int (*fp0)(void);
typedef int (*fp1)(int);
typedef int (*fp2)(int,int);
typedef int (*fp3)(int,int,int);
typedef int (*fp4)(int,int,int,int);
bool invoke……
[/Quote]
太感谢了。学习中...
redleaves 2011-06-22
  • 打赏
  • 举报
回复
#include <stdio.h>
typedef int (*fp0)(void);
typedef int (*fp1)(int);
typedef int (*fp2)(int,int);
typedef int (*fp3)(int,int,int);
typedef int (*fp4)(int,int,int,int);
bool invoke_dispatch( int *ret, void *func, int num, int *param ) {
switch( num ) {
case 0:
*ret = ((fp0)func)();
break;
case 1:
*ret = ((fp1)func)(param[0]);
break;
case 2:
*ret = ((fp2)func)(param[0],param[1]);
break;
case 3:
*ret = ((fp3)func)(param[0],param[1],param[2]);
break;
case 4:
*ret = ((fp4)func)(param[0],param[1],param[2],param[3]);
break;
default:
return false;
}
return true;
}

int main() {
int params[256];
params[0] = (int)"hello world %d %f\n";
params[1] = (int)123456;
((double*)&(params[2]))[0] = 12.34;

int ret;
invoke_dispatch( &ret, (void*)printf, 4, params );
return 0;
}

给你一段可以实际运行的代码.
另外,上面说double要翻转在x86上可以无视.
lonelyrains 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 redleaves 的回复:]
引用 29 楼 lonelyrains 的回复:谢谢红叶兄的指点。我目前就是按照这个分包做的,处理能力在3个参数以内,支持int/char/double/int */char */double *,代码量已经超级多,大量结构重复的代码,令我痛苦不堪。c++解释器,得研究研究。你没有注意我说的最后一句话...
做分派机制的时候,不用考虑类型.
比如要调用int func(double);
因为……
[/Quote]
还是不理解。typedef定义的指针类型的时候不也还是要一个一个的定义吗?而且参数列表总空间大小相同但是列表不同的函数怎么分开打包?是不是要用存放每个参数的大小的列表区分了?
redleaves 2011-06-22
  • 打赏
  • 举报
回复
另外,上面的代码是随手写的,不完全正确,double拆成int应该要按4字节翻转一下才对.但方法肯定是没错的.
redleaves 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 lonelyrains 的回复:]谢谢红叶兄的指点。我目前就是按照这个分包做的,处理能力在3个参数以内,支持int/char/double/int */char */double *,代码量已经超级多,大量结构重复的代码,令我痛苦不堪。c++解释器,得研究研究。[/Quote]你没有注意我说的最后一句话...
做分派机制的时候,不用考虑类型.
比如要调用int func(double);
因为double长度是8,只要相应调用参数长度是8的函数就可以.
也就是说func( 1.1 );
用上面分派的方式要变成
int param[2];
*((double*)param) = 1.1; // 打包的时候按类型打包
int ret;
invoke_dispatch(&ret, (void*)func, 2, param); // 调用和类型是无关的
所以,并不会因为类型因素而导致代码爆炸性增长.
lonelyrains 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 redleaves 的回复:]
引用 22 楼 lonelyrains 的回复:其实这个问题的来源是我想写一个针对所有动态库中的函数的调用测试MFC工程。
比如动态库中有一个函数int add(int a,int b),用户只用在文本框中输入int add(int 3,int 4)和该函数所在的dll路径,点击运行,马上就可以输出返回值。
我所知的调用dll中函数的方式:先定义函数指针类型:typedef int (WINA……
[/Quote]
谢谢红叶兄的指点。我目前就是按照这个分包做的,处理能力在3个参数以内,支持int/char/double/int */char */double *,代码量已经超级多,大量结构重复的代码,令我痛苦不堪。c++解释器,得研究研究。
redleaves 2011-06-22
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 lonelyrains 的回复:]其实这个问题的来源是我想写一个针对所有动态库中的函数的调用测试MFC工程。
比如动态库中有一个函数int add(int a,int b),用户只用在文本框中输入int add(int 3,int 4)和该函数所在的dll路径,点击运行,马上就可以输出返回值。
我所知的调用dll中函数的方式:先定义函数指针类型:typedef int (WINAPI ADD)(int a,int b);然后定义该指针类型的指针,赋值为LoadLibrary的返回值。问题是要针对动态库中所有的函数,就涉及到很多种数据类型和参数列表组合。如何针对复杂多变的函数,定义指针类型?[/Quote]这种功能超出了C++本身的能力了.你只能用汇编来搞.无非就是几个push一个call而已.但解析用户输入又是另一门学问了.也许那些C/C++的解释器更适合你.比如CINT,CH之类的.
当然,如果用一些比较变态的手段,在一定程度上,只用C/C++也能完成你要的功能.
方法如下:
定义
typedef int (*fp0)(void);
typedef int (*fp1)(int);
....
typedef int (*fpn)(int,....,int);
然后做个参数打包分派机制.
bool invoke_dispatch( int *ret, void *func, int num, int *param ) {
switch( num ) {
case 0:
*ret = ((fp0)func)();
break;
case 1;
*ret = ((fp0)func)(param[0]);
break;
....
default;
return false;
}
return true;
}
要动态调用的时候只要把参数打包,然后分派一下就可以了.这种方式的局限性是分派的能力是代码限定死的.参数长度超出分派机制能力的,就不行了.但好处是实现简单,可移植性很好.
另一种分派方案是用alloca来建立参数栈.然后调用函数.这种方式可以适应任意长度的参数,但不同的平台,调用函数的方法不同,移植性不好.
要注意的是,参数的类型在分派的时候是不用考虑的.只要打包的时候按类型正确打包即可.
lonelyrains 2011-06-21
  • 打赏
  • 举报
回复
[Quote=引用 20 楼 iambic 的回复:]
很多人(主要是一些初学者)之所以要求看起来很高端的东西,都是因为基础的东西都没掌握,就要凭着自己的幻想以为这些简单的东西需要多高科技的特性来完成。初学者应该踏踏实实的,先充分利用手中已有的工具去尝试解决问题。
[/Quote]
其实这个问题的来源是我想写一个针对所有动态库中的函数的调用测试MFC工程。
比如动态库中有一个函数int add(int a,int b),用户只用在文本框中输入int add(int 3,int 4)和该函数所在的dll路径,点击运行,马上就可以输出返回值。
我所知的调用dll中函数的方式:先定义函数指针类型:typedef int (WINAPI ADD)(int a,int b);然后定义该指针类型的指针,赋值为LoadLibrary的返回值。问题是要针对动态库中所有的函数,就涉及到很多种数据类型和参数列表组合。如何针对复杂多变的函数,定义指针类型?
lonelyrains 2011-06-21
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 hpsmouse 的回复:]
引用 17 楼 lonelyrains 的回复:
动态语言能架设服务器写嵌入式吗?我只是在想能不能用C++实现这个功能。貌似结果大家都认为不行。再看看动态类型识别是怎么回事的,也许有启示

现在用动态语言写的服务器端程序也不少了。

嵌入式的话,至少我手机上的 Python 还是跑得挺顺畅的~

言归正传,你的最初需求是在运行期生成可以执行的代码没错吧?

C/C++ 的可执行代……
[/Quote]
请问可以具体解释一下第三点吗?不好意思~
iambic 2011-06-21
  • 打赏
  • 举报
回复
很多人(主要是一些初学者)之所以要求看起来很高端的东西,都是因为基础的东西都没掌握,就要凭着自己的幻想以为这些简单的东西需要多高科技的特性来完成。初学者应该踏踏实实的,先充分利用手中已有的工具去尝试解决问题。
2011-06-21
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 lonelyrains 的回复:]
动态语言能架设服务器写嵌入式吗?我只是在想能不能用C++实现这个功能。貌似结果大家都认为不行。再看看动态类型识别是怎么回事的,也许有启示
[/Quote]
现在用动态语言写的服务器端程序也不少了。

嵌入式的话,至少我手机上的 Python 还是跑得挺顺畅的~

言归正传,你的最初需求是在运行期生成可以执行的代码没错吧?

C/C++ 的可执行代码通常都只有一种形式:机器指令。而且 C/C++ 的标准库里面没有提供 C/C++ 的解释器,我见过的大多数系统也不提供这样的解释器。

在 C/C++ 的环境下,要实现动态生成代码,我知道的有这么几个办法:

1. 直接动态生成机器码。比较麻烦,而且严重依赖平台,唯一的优点是这样生成的代码可以达到比较高的效率。

2. 实现一个解释器。这个和生成机器码几乎一样麻烦,甚至比生成机器码还要麻烦。

3. 利用 C++ 的模板和继承等手段变相实现动态代码生成。这个几乎已经不算“代码生成”了,而且程序的部分结构需要重新设计。不过这其实是比较常用的手段……
taodm 2011-06-21
  • 打赏
  • 举报
回复
动态语言当然能架设服务器写嵌入式。erlang不是吃干饭的。
lonelyrains 2011-06-21
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 hpsmouse 的回复:]
引用 13 楼 lonelyrains 的回复:
字符串可以用代码处理,你这样写,参数能处理吗?怎么回答:例如有100个宏,分别为M1,M2,M3,M4....M100,假设均为字符串(#define M1 "helloworld")。如……

在“可以用代码处理”的时候,宏早就不能起作用了。

宏是在编译之前就要完全展开的。

趁早换动态语言,C 不适合你……
[/Quote]
动态语言能架设服务器写嵌入式吗?我只是在想能不能用C++实现这个功能。貌似结果大家都认为不行。再看看动态类型识别是怎么回事的,也许有启示
skyworth98 2011-06-21
  • 打赏
  • 举报
回复
sp......

[Quote=引用 14 楼 hpsmouse 的回复:]
引用 13 楼 lonelyrains 的回复:
字符串可以用代码处理,你这样写,参数能处理吗?怎么回答:例如有100个宏,分别为M1,M2,M3,M4....M100,假设均为字符串(#define M1 "helloworld")。如……

在“可以用代码处理”的时候,宏早就不能起作用了。

宏是在编译之前就要完全展开的。

趁早换动态语言,C 不适合你……
[/Quote]
healer_kx 2011-06-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 lonelyrains 的回复:]

引用 1 楼 healer_kx 的回复:
很多语言支持eval。
我想你明白了我的意思,但是eval只是执行一点脚本,而内部脚本串根本不能拿到当前代码中混用。例如eval串中定义的变量不能拿到当前代码中来调用,是吧?
[/Quote]

感谢你支持C++,这么高看C++,哥能理解你,但是帮不了你。

Ruby才有这种eval,C++下辈子也不会有的。
加载更多回复(14)

64,646

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧