0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何給一個(gè)變量設(shè)置一個(gè)別名?

strongerHuang ? 來源:IOT物聯(lián)網(wǎng)小鎮(zhèn) ? 作者:IOT物聯(lián)網(wǎng)小鎮(zhèn) ? 2022-06-06 09:33 ? 次閱讀

別名是啥玩意?

stackoverflow上看到一個(gè)有趣的話題:如何給一個(gè)變量設(shè)置一個(gè)別名?(How to assign to a variable an alias?

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

所謂的變量別名,就是通過通過不同的標(biāo)識(shí)符,來表示同一個(gè)變量。

我們知道,變量名稱是給程序員使用的。

編譯器的眼中,所有的變量都變成了地址

請注意:這里所討論的別名,僅僅是通過不同的標(biāo)識(shí)符來引用同一個(gè)變量。

與強(qiáng)符號、弱符號的概念沒有任何關(guān)系,那是另一個(gè)話題。

在上面這個(gè)帖子中,作者首先想到的是通過宏定義,對變量進(jìn)行重新命名。

這樣的做法,將會(huì)在編譯之前的預(yù)處理環(huán)節(jié),把宏標(biāo)識(shí)符替換為變量標(biāo)識(shí)符。

在網(wǎng)友回復(fù)的答案中,大部分都是通過指針來實(shí)現(xiàn):讓不同的標(biāo)識(shí)符指向同一個(gè)變量。

不管怎么說,這也算是一種別名了。

但是,這些答案有一個(gè)局限:這些代碼必須一起進(jìn)行編譯才可以,否則就可能出現(xiàn)無法找到符號的錯(cuò)誤信息

現(xiàn)在非常流行插件編程,如果開發(fā)者想在插件中通過一個(gè)變量別名來引用主程序中的變量,這該如何處理呢?

本文提供兩個(gè)方法來實(shí)現(xiàn)這個(gè)目的,并通過兩個(gè)簡單的示例代碼來進(jìn)行演示。

文末有示例代碼的下載地址。

方法1:反向注冊

之前我接觸過一些CodeSys的代碼,里面的代碼質(zhì)量真的是非常的高,特別是軟件架構(gòu)設(shè)計(jì)部分。

傳說:CodySys 是工控界的 Android。

其中有個(gè)反向注冊的想法,正好可以用在變量別名上面。

示例代碼中一共有 2 個(gè)文件:main.cplugin.c。

main.c中定義了一個(gè)全局變量數(shù)組,編譯成可執(zhí)行程序main。

plugin.c中通過一個(gè)別名來使用main.c中的全局變量。

plugin.c被編譯成一個(gè)動(dòng)態(tài)鏈接庫,被可執(zhí)行程序main動(dòng)態(tài)加載(dlopen)。

plugin.c中,提供一個(gè)函數(shù)func_init,當(dāng)動(dòng)態(tài)庫被main dlopen之后,這個(gè)函數(shù)就被調(diào)用,并且把真正的全局變量的地址通過參數(shù)傳入

這樣的話,在插件中就可以通過一個(gè)別名來使用真正的變量了(比如:修改變量的值)。

本質(zhì)上,這仍然是通過指針來進(jìn)行引用。

只不過利用動(dòng)態(tài)注冊的思想,把指針與變量的綁定關(guān)系在時(shí)間和空間上進(jìn)行隔離。

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

執(zhí)行結(jié)果:

data[0] = 10 
data[1] = 20 
libplugin.so: func_init is called. 
libplugin.so: func_stage1 is called. 
data[0] = 100 
data[1] = 200

可以看一下動(dòng)態(tài)鏈接庫的符號表:

readelf -s libplugin.so | grep data
4ee38580-e530-11ec-ba43-dac502259ad0.png

可以看到alias_data標(biāo)識(shí)符,并且是在本文件中定義的全局變量。

方法2:嵌入?yún)R編代碼

在動(dòng)態(tài)加載的插件中使用變量別名,除了上面演示的動(dòng)態(tài)注冊的方式,還可以通過嵌入?yún)R編代碼來: 設(shè)置一個(gè)全局標(biāo)號來實(shí)現(xiàn)。

直接上示例代碼:

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

執(zhí)行結(jié)果:

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

小結(jié)

這篇文檔通過兩個(gè)示例代碼,討論了如何在插件中(動(dòng)態(tài)鏈接庫),通過別名來訪問真正的變量。

不知道您會(huì)不會(huì)有這樣的疑問:直接使用extern來聲明一下外部定義的變量不就可以了,何必這么麻煩?

道理是沒錯(cuò)!

但是,在一些比較特殊的領(lǐng)域或場景中(比如一些二次開發(fā)中),這樣的需求是的確存在的,而且是強(qiáng)需求。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4260

    瀏覽量

    62228
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4697

    瀏覽量

    68083
  • 變量
    +關(guān)注

    關(guān)注

    0

    文章

    609

    瀏覽量

    28288

原文標(biāo)題:如何給全局變量起一個(gè)別名?

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    文帶你了解IP地址別名

    、什么是IP地址別名 IP地址別名是將多個(gè)IP地址與個(gè)網(wǎng)絡(luò)接口關(guān)聯(lián)起來的種方式。實(shí)現(xiàn)在網(wǎng)絡(luò)
    的頭像 發(fā)表于 09-05 14:11 ?144次閱讀

    電感的電流能否分流一個(gè)電感

    電感的電流能否分流一個(gè)電感,這個(gè)問題涉及到電感器的工作原理、特性以及在電路中的應(yīng)用。 電感器的基本概念 電感器是種被動(dòng)電子元件,其主要功能是存儲(chǔ)能量。電感器由
    的頭像 發(fā)表于 08-21 10:02 ?208次閱讀

    個(gè)輕量級的LED控制模塊

    比如LED周期控制函數(shù)為100ms,理論上設(shè)置500ms間隔閃爍,則需要占用10個(gè)bit,但是增加個(gè)bit時(shí)間顆粒度變量,只需要占用兩
    發(fā)表于 02-29 11:43 ?433次閱讀

    為什么要給放大器設(shè)置個(gè)工作點(diǎn)

    在設(shè)計(jì)放大器的時(shí)候,我們都會(huì)給放大器設(shè)置個(gè)工作點(diǎn),所謂工作點(diǎn),就是指管子在直流工作狀態(tài)下,對應(yīng)的電壓和電流。
    的頭像 發(fā)表于 01-26 10:29 ?692次閱讀
    為什么要給放大器<b class='flag-5'>設(shè)置</b><b class='flag-5'>一</b><b class='flag-5'>個(gè)</b>工作點(diǎn)

    程序中增加個(gè)變量導(dǎo)致異常的分析

    大家在平常的編程過程應(yīng)該會(huì)碰到各種奇葩的問題吧,反正我最近是碰到了次,再此跟大家分享下。事情的原因是我在程序中增加了個(gè)變量,然后就會(huì)導(dǎo)
    的頭像 發(fā)表于 01-22 09:56 ?444次閱讀
    程序中增加<b class='flag-5'>一</b><b class='flag-5'>個(gè)</b><b class='flag-5'>變量</b>導(dǎo)致異常的分析

    softune如何把個(gè)變量定義在指定RAM地址?

    你好,請問如何把個(gè)變量定義在指定RAM地址? 例如把 i 變量定義在 RAM地址 0x0200,謝謝!
    發(fā)表于 01-18 10:48

    使用小安派做一個(gè)智能家居中控

    個(gè)消息框設(shè)置成時(shí)間,這里服務(wù)器設(shè)置個(gè)MQTT
    的頭像 發(fā)表于 01-07 10:01 ?529次閱讀
    使用小安派做<b class='flag-5'>一個(gè)</b>智能家居中控

    ros怎么設(shè)置環(huán)境變量

    設(shè)置ROS環(huán)境變量是使用ROS的重要步驟之。本文將詳細(xì)介紹如何設(shè)置ROS環(huán)境變量,包括什么是環(huán)境變量
    的頭像 發(fā)表于 12-28 13:52 ?1770次閱讀

    如何設(shè)置個(gè)路由器使用同一個(gè)Wi-Fi網(wǎng)絡(luò)?

    如何設(shè)置個(gè)路由器使用同一個(gè)Wi-Fi網(wǎng)絡(luò) 隨著無線網(wǎng)絡(luò)的普及和需求量的增加,很多家庭和辦公室都會(huì)購買多個(gè)路由器來擴(kuò)展無線網(wǎng)絡(luò)覆蓋范圍。然而,許多人可能不知道如何正確設(shè)置
    的頭像 發(fā)表于 12-11 10:50 ?1.2w次閱讀

    如何逐步設(shè)置并從ADC讀取個(gè)結(jié)果

    電子發(fā)燒友網(wǎng)站提供《如何逐步設(shè)置并從ADC讀取個(gè)結(jié)果.pdf》資料免費(fèi)下載
    發(fā)表于 11-27 11:44 ?0次下載
    如何逐步<b class='flag-5'>設(shè)置</b>并從ADC讀取<b class='flag-5'>一</b><b class='flag-5'>個(gè)</b>結(jié)果

    python里怎么寫個(gè)數(shù)的立方

    在Python中,我們可以使用運(yùn)算符和函數(shù)來計(jì)算數(shù)的立方。下面我將詳細(xì)介紹如何使用這些方法來實(shí)現(xiàn)這個(gè)功能。 首先,我們可以使用乘法運(yùn)算符 ** 來計(jì)算個(gè)數(shù)的立方。例如,如果我們有個(gè)
    的頭像 發(fā)表于 11-21 16:47 ?3074次閱讀

    ROS主控如何創(chuàng)建設(shè)備別名

    創(chuàng)建設(shè)備別名 需要?jiǎng)?chuàng)建設(shè)備別名原因: 在運(yùn)行個(gè)ros程序的時(shí)候需要提供個(gè)端口名,這個(gè)端口名
    的頭像 發(fā)表于 11-17 18:07 ?650次閱讀
    ROS主控如何創(chuàng)建設(shè)備<b class='flag-5'>別名</b>

    個(gè)函數(shù)返回的類型是枚舉,能不能將此狀態(tài)賦值個(gè)char呢?

    個(gè)函數(shù)返回的類型是枚舉類型,現(xiàn)在我在另外的個(gè)子程序中調(diào)用了這個(gè)函數(shù),能不能將此函數(shù)的返回狀態(tài)賦值
    發(fā)表于 11-10 06:11

    keil5 debug的時(shí)候,如何查看個(gè)具體的變量

    keil5 debug的時(shí)候,如何查看個(gè)具體的變量,而且讓這個(gè)變量能實(shí)時(shí)更新
    發(fā)表于 11-01 06:24

    51單片機(jī)中,如何把兩個(gè)數(shù)組的數(shù)合在起然后個(gè)變量?

    51單片機(jī)中,怎么兩個(gè)數(shù)組的數(shù)合在起然后個(gè)變量 比如:char a[5]={01234} char b[5]={56789} char
    發(fā)表于 10-31 07:34