0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何给一个变量设置一个别名?

strongerHuang ? 来源:IOT物联网小镇 ? 作者:IOT物联网小镇 ? 2022-06-06 09:33 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

别名是啥玩意?

stackoverflow上看到一个有趣的话题:如何给一个变量设置一个别名?(How to assign to a variable an alias?

4eaada1e-e530-11ec-ba43-dac502259ad0.png

所谓的变量别名,就是通过通过不同的标识符,来表示同一个变量。

我们知道,变量名称是给程序员使用的。

编译器的眼中,所有的变量都变成了地址

请注意:这里所讨论的别名,仅仅是通过不同的标识符来引用同一个变量。

与强符号、弱符号的概念没有任何关系,那是另一个话题。

在上面这个帖子中,作者首先想到的是通过宏定义,对变量进行重新命名。

这样的做法,将会在编译之前的预处理环节,把宏标识符替换为变量标识符。

在网友回复的答案中,大部分都是通过指针来实现:让不同的标识符指向同一个变量。

不管怎么说,这也算是一种别名了。

但是,这些答案有一个局限:这些代码必须一起进行编译才可以,否则就可能出现无法找到符号的错误信息。

现在非常流行插件编程,如果开发者想在插件中通过一个变量别名来引用主程序中的变量,这该如何处理呢?

本文提供两个方法来实现这个目的,并通过两个简单的示例代码来进行演示。

文末有示例代码的下载地址。

方法1:反向注册

之前我接触过一些CodeSys的代码,里面的代码质量真的是非常的高,特别是软件架构设计部分。

传说:CodySys 是工控界的 Android

其中有个反向注册的想法,正好可以用在变量别名上面。

示例代码中一共有 2 个文件:main.cplugin.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. 
");
alias_data = data;
}

void func_stage1(void)
{
printf("libplugin.so: func_stage1 is called. 
");
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 
", data[0]);
printf("data[1] = %d 
", data[1]);

// open libplugin.so
void *handle = dlopen("./libplugin.so", RTLD_NOW);
if (!handle)
{
printf("dlopen failed. 
");
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. 
");
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. 
");
return;
}
func_stage1();

printf("data[0] = %d 
", data[0]);
printf("data[1] = %d 
", 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
4ee38580-e530-11ec-ba43-dac502259ad0.png

可以看到alias_data标识符,并且是在本文件中定义的全局变量。

方法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. 
");

*(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 
", data[0]);
printf("data[1] = %d 
", data[1]);

// open libplugin.so
void *handle = dlopen("./libplugin.so", RTLD_NOW);
if (!handle)
{
printf("dlopen failed. 
");
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. 
");
return;
}
func_stage1();

printf("data[0] = %d 
", data[0]);
printf("data[1] = %d 
", 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
4f4798ea-e530-11ec-ba43-dac502259ad0.png

小结

这篇文档通过两个示例代码,讨论了如何在插件中(动态链接库),通过别名来访问真正的变量。

不知道您会不会有这样的疑问:直接使用extern来声明一下外部定义的变量不就可以了,何必这么麻烦?

道理是没错!

但是,在一些比较特殊的领域或场景中(比如一些二次开发中),这样的需求是的确存在的,而且是强需求。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 函数
    +关注

    关注

    3

    文章

    4388

    浏览量

    65397
  • 代码
    +关注

    关注

    30

    文章

    4908

    浏览量

    71297
  • 变量
    +关注

    关注

    0

    文章

    614

    浏览量

    29096

原文标题:如何给全局变量起一个别名?

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【原创】TDMS设置一个写入位置函数的摸索

    开时,必须启用缓冲 3、必须先调用“tdms设置一个写入位置”再调用高级tdms写入函数 4、写入函数完成后,必须使用高级tdms关闭,利用刷新是无用的 5、高级tdms打开函数,生成的tdms引用放入全局变量,然后在其他vi
    发表于 08-11 20:54

    如何打造属于自己的手势识别应用

    期小编大家介绍了和MediaPipe的相遇之路,本期小编将带着大家起来动手,如何打造属于自己的手势识别应用。
    的头像 发表于 07-29 10:12 ?357次阅读
    如何打造<b class='flag-5'>一</b><b class='flag-5'>个</b>属于自己的手势识别应用

    Keysight是德示波器的5触发设置与波形分析方法

    Keysight是德示波器在电子测量领域应用广泛,精准的触发设置与高效的波形分析方法对获取准确信号信息至关重要。以下为您介绍5常用的触发设置及波形分析方法。 ? 边沿触发设置? 边沿
    的头像 发表于 06-27 16:00 ?538次阅读
    Keysight是德示波器的5<b class='flag-5'>个</b>触发<b class='flag-5'>设置</b>与波形分析方法

    关于STM32 CAN通信发送函数HAL_CAN_AddTxMessage()的最后参数填0和定义变量取地址的问题求解

    问题: 关于STM32 CAN通信 发送函数 HAL_CAN_AddTxMessage()的最后参数填0和定义变量取地址的问题,如果
    发表于 03-11 08:22

    设置让 KiCad 的视觉体验提升档次!

    “ ?不知道您有没有感觉到无论是原理图还是PCB,KiCad 没有商业软件看上去那么清晰?其实只需要手动改下这个设置,瞬间让您的视觉体验提升档次!? ” ? ? 使用 KiCad
    的头像 发表于 02-17 11:17 ?1106次阅读
    <b class='flag-5'>一</b><b class='flag-5'>个</b><b class='flag-5'>设置</b>让 KiCad 的视觉体验提升<b class='flag-5'>一</b><b class='flag-5'>个</b>档次!

    自己动手做一个好玩的POV显示设备

    “ 读大学的时候就很喜欢这些开脑洞的小玩意儿。看到印度小哥用ESP32 做了高分辨率的 POV,而且开源了全部的硬件和代码,忍不住想分享大家。”
    的头像 发表于 12-25 15:15 ?1826次阅读
    自己动手做<b class='flag-5'>一个</b>好玩的POV显示设备

    如何构建演示移动端应用

    作为通讯工具,视频会议几乎随处可见,尤其适用于远程办公和社交互动。但其使用体验并非总是简单直接、即开即用,可能需要进行调整,确保音频视频设置良好。其中,照明便是难以把握的因素。在会议中,光线充足
    的头像 发表于 11-15 11:43 ?613次阅读
    如何构建<b class='flag-5'>一</b><b class='flag-5'>个</b>演示移动端应用

    分享keil MDK编译信息增强工具

    今天大家分享 keil MDK 编译信息增强工具:keil-build-viewer. 1 keil-build-viewer介绍 这是
    的头像 发表于 11-14 11:01 ?2000次阅读

    如何在文本字段中使用上标、下标及变量

    在KiCad的任何文本字段中,都可以通过以下的方式实现上标、下标、上划线以及显示变量及字段值的描述: 文本变量“文本变量”可以在 原理图设置->工程->文本
    的头像 发表于 11-12 12:23 ?763次阅读
    如何在文本字段中使用上标、下标及<b class='flag-5'>变量</b>

    Lua语法基础教程(中篇)

    今天我们继续学习Lua语法基础教程,中篇。 五、变量 5.1 number变量 变量,可以看作是桶,在里面装你想要装的内容。这些内容可以
    的头像 发表于 10-26 11:39 ?887次阅读
    Lua语法基础教程(中篇)

    Linux环境变量配置方法

    Linux上环境变量配置分为设置永久变量和临时变量两种。环境变量设置方法同时要考虑环境Shell
    的头像 发表于 10-23 13:39 ?884次阅读

    Xilinx设计工具怎么设置环境变量

    如果您不确定如何设置环境变量,尝试"1" 或 "TRUE"。
    的头像 发表于 10-22 13:32 ?719次阅读

    双开关控制灯怎么接线

    双开关控制灯的接线方法主要有以下几种,每种方法都有其特定的应用场景和接线方式: 、串联接线法 接线步骤 : 将电源线的火线(L)与
    的头像 发表于 10-09 15:57 ?1.5w次阅读

    文带你了解IP地址别名

    、什么是IP地址别名 IP地址别名是将多个IP地址与网络接口关联起来的种方式。实现在网络
    的头像 发表于 09-05 14:11 ?641次阅读

    ad如何设置元器件的距离

    之间应保持的最小距离,以确保电路板的电气性能和制造过程的可靠性。以下是如何在AD中设置元器件之间距离的步骤: 、进入规则设置界面 打开AD软件 :首先,确保你已经打开了Altiu
    的头像 发表于 09-02 15:31 ?1.8w次阅读