当前位置:网站首页>C语言:如何给全局变量起一个别名?
C语言:如何给全局变量起一个别名?
2022-06-13 07:18:00 【qq_43479892】
优质资源分享
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
Python量化交易实战 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++、嵌入式、Linux。
关注下方公众号,回复【书籍】,获取 Linux、嵌入式领域经典书籍;回复【PDF】,获取所有原创文章( PDF 格式)。
目录
目录* 别名是啥玩意?
别人的经验,我们的阶梯!
别名是啥玩意?
在stackoverflow
上看到一个有趣的话题:如何给一个变量设置一个别名?(How to assign to a variable an alias?
)
所谓的变量别名,就是通过通过不同的标识符,来表示同一个变量。
我们知道,变量名称是给程序员使用的。
在编译器的眼中,所有的变量都变成了地址。
请注意:这里所讨论的别名,仅仅是通过不同的标识符来引用同一个变量。
与强符号、弱符号没有关系,那是另一个话题。
在上面这个帖子中,作者首先想到的是通过宏定义,对变量进行重新命名。
这样的做法,将会在编译之前的预处理环节,把宏标识符替换为变量标识符。
在网友回复的答案中,大部分都是通过指针来实现:让不同的标识符指向同一个变量。
不管怎么说,这也算是一种别名了。
但是,这些答案有一个局限:这些代码必须一起进行编译才可以,否则就可能出现无法找到符号的错误信息。
现在非常流行插件编程,如果开发者想在插件中通过一个变量别名来引用主程序中的变量,这该如何处理呢?
本文提供两个方法来实现这个目的,并通过两个简单的示例代码来进行演示。
文末有示例代码的下载地址。
方法1:反向注册
之前我接触过一些CodeSys
的代码,里面的代码质量真的是非常的高,特别是软件架构设计部分。
传说:CodySys 是工控界的 Android。
其中有个反向注册的想法,正好可以用在变量别名上面。
示例代码中一共有 2 个文件:main.c
和plugin.c
。
main.c
中定义了一个全局变量数组,编译成可执行程序main
。
plugin.c
中通过一个别名来使用main.c
中的全局变量。
plugin.c
被编译成一个动态链接库,被可执行程序main
动态加载(dlopen
)。
在plugin.c
中,提供一个函数func_init
,当动态库被main
dlopen
之后,这个函数就被调用,并且把真正的全局变量的地址通过参数传入。
这样的话,在插件中就可以通过一个别名来使用真正的变量了(比如:修改变量的值)。
本质上,这仍然是通过指针来进行引用。
只不过利用动态注册的思想,把指针与变量的绑定关系在时间和空间上进行隔离。
plugin.c 源文件
#include
int *alias_data = NULL;
void func\_init(int *data)
{
printf("libplugin.so: func\_init is called. \n");
alias_data = data;
}
void func\_stage1(void)
{
printf("libplugin.so: func\_stage1 is called. \n");
if (alias_data)
{
alias_data[0] = 100;
alias_data[1] = 200;
}
}
main.c 源文件
#include
#include
#include
// defined in libplugin.so
typedef void (*pfunc\_init)(int *);
typedef void (*pfunc\_stage1)(void);
int data[100] = { 0 };
void main(void)
{
data[0] = 10;
data[1] = 20;
printf("data[0] = %d \n", data[0]);
printf("data[1] = %d \n", data[1]);
// open libplugin.so
void *handle = dlopen("./libplugin.so", RTLD_NOW);
if (!handle)
{
printf("dlopen failed. \n");
return;
}
// get and call init function in libplugin.so
pfunc_init func_init = (pfunc_init) dlsym(handle, "func\_init");
if (!func_init)
{
printf("get func\_init failed. \n");
return;
}
func\_init(data);
// get and call routine function in libplugin.so
pfunc_stage1 func_stage1 = (pfunc_stage1) dlsym(handle, "func\_stage1");
if (!func_stage1)
{
printf("get func\_stage1 failed. \n");
return;
}
func\_stage1();
printf("data[0] = %d \n", data[0]);
printf("data[1] = %d \n", data[1]);
return;
}
编译指令如下:
gcc -m32 -fPIC --shared plugin.c -o libplugin.so
gcc -m32 -o main main.c -ldl
执行结果:
data[0] = 10
data[1] = 20
libplugin.so: func_init is called.
libplugin.so: func_stage1 is called.
data[0] = 100
data[1] = 200
可以看一下动态链接库的符号表:
readelf -s libplugin.so | grep data
可以看到alias_data
标识符,并且是在本文件中定义的全局变量。
【关于作者】
号主:道哥,十多年的嵌入式开发老兵,专注于嵌入式 + Linux 领域,玩过单片机、搞过智能家居、研究过 PLC 和 工业机器人,项目开发经验非常丰富。
他的文章主要包括 C/C++、Linux操作系统、物联网、单片机和嵌入式这几个方面。
厚积薄发、换位思考,以读者的角度来总结文章。
每一篇输出,不仅仅是干货的呈现,更是引导你一步一步的深入思考,从底层逻辑来提升自己。
方法2:嵌入汇编代码
在动态加载的插件中使用变量别名,除了上面演示的动态注册的方式,还可以通过嵌入汇编代码来: 设置一个全局标号来实现。
直接上示例代码:
plugin.c
源文件
#include
asm(".Global alias\_data");
asm("alias\_data = data");
extern int alias_data[];
void func\_stage1(void)
{
printf("libplugin.so: func\_stage1 is called. \n");
*(alias_data + 0) = 100;
*(alias_data + 1) = 200;
}
main.c
源文件
#include
#include
#include
// defined in libplugin.so
typedef void (*pfunc\_init)(int *);
typedef void (*pfunc\_stage1)(void);
int data[100] = { 0 };
void main(void)
{
data[0] = 10;
data[1] = 20;
printf("data[0] = %d \n", data[0]);
printf("data[1] = %d \n", data[1]);
// open libplugin.so
void *handle = dlopen("./libplugin.so", RTLD_NOW);
if (!handle)
{
printf("dlopen failed. \n");
return;
}
// get and call routine function in libplugin.so
pfunc_stage1 func_stage1 = (pfunc_stage1) dlsym(handle, "func\_stage1");
if (!func_stage1)
{
printf("get func\_stage1 failed. \n");
return;
}
func\_stage1();
printf("data[0] = %d \n", data[0]);
printf("data[1] = %d \n", data[1]);
return;
}
编译指令:
gcc -m32 -fPIC --shared plugin.c -o libplugin.so
gcc -m32 -rdynamic -o main main.c -ldl
执行结果:
data[0] = 10
data[1] = 20
libplugin.so: func_stage1 is called.
data[0] = 100
data[1] = 200
也来看一下libplugin.so
中的符号信息:
readelf -s libplugin.so | grep data
小结
这篇文档通过两个示例代码,讨论了如何在插件中(动态链接库),通过别名来访问真正的变量。
不知道您会不会有这样的疑问:直接使用extern
来声明一下外部定义的变量不就可以了,何必这么麻烦?
道理是没错!
但是,在一些比较特殊的领域或场景中(比如一些二次开发中),这样的需求是的确存在的,而且是强需求。
如果你有任何疑问,或者文中有任务错误,欢迎留言讨论、指正。
------ End ------
在公众号【IOT物联网小镇】后台回复关键字:20522,即可获取示例代码的下载地址。
既然看到这里了,如果觉得不错,请您随手点个【赞】和【在看】吧!
如果转载本文,文末务必注明:“转自微信公众号:IOT物联网小镇”。
推荐阅读
【2】C语言指针-从底层原理到花式技巧,用图文和代码帮你讲解透彻
【4】Linux中对【库函数】的调用进行跟踪的3种【插桩】技巧
【6】gcc编译时,链接器安排的【虚拟地址】是如何计算出来的?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rFqdaaIG-1655053816259)(https://img2022.cnblogs.com/blog/1440498/202206/1440498-20220612215545217-1664410615.png)]
星标公众号,第一时间看文章!
边栏推荐
猜你喜欢
Normalizing y-axis in histograms in R ggplot to proportion
Make cer/pfx public and private key certificates and export CFCA application certificates
Tidb grafana reverse proxy
The password does not take effect after redis is set
Tikv key performance parameters and optimization
Ticdc introduction
Compilation and development process of Quanzhi v3s environment
基于ESP32CAM实现WebSocket服务器实时点灯
It's called the next generation monitoring system. Let's see how awesome it is
Department store center supply chain management system
随机推荐
Raspberry school advanced development - "writing of IO port driver code" includes bus address, physical \u virtual address and bcm2835 chip manual knowledge
How is it that the income of financial products is zero for several consecutive days?
ISIS的vsys(虚拟系统)
Test development programmers, are you still confused? You can't define yourself as a yard farmer
The password does not take effect after redis is set
Ansible PlayBook的中清单变量优先级分析及清单变量如何分离总结
【硬记】脏读、不可重复读、幻读场景核心区别
Detailed description of drawing ridge plot, overlapping densities of overlapping kernel density estimation curve, facetgrid object and function sns Kdeplot, function facetgrid map
It's called the next generation monitoring system. Let's see how awesome it is
c#高級編程-特性篇
oracle问题,字段里面的数据被逗号隔开,取逗号两边数据
Simple understanding of basic language of C language
对绘制丘岭密度图ridge plot的详细说明、重叠核密度估计曲线overlapping densities、FacetGrid对象、函数sns.kdeplot、函数FacetGrid.map
FTP_ Manipulate remote files
TiDB Lightning
Postgraduate entrance examination English
How to stop PHP FPM service in php7
I always don't understand the high address and high position
Make cer/pfx public and private key certificates and export CFCA application certificates
One article of quantitative framework backtrader read analyzer