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

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

3天内不再提示

【知识科普】C语言的static究竟限制了谁

RTThread物联网操作系统 来源:未知 2023-08-02 20:05 次阅读

【知识科普C语言的static究竟限制了谁?

这是一个有趣的话题,虽然说教科书给了你一些说法,但你真正能把static说清楚吗?本文将通过一个案例,给大家做一个深度的拆解分析。

注:在本文的讨论中,无明确说明时,指的都是static修饰函数,而非变量。

1 问题来源


最近的几个月一直在维护我的个人专属【嵌入式技术交流群】,平时大家都很积极在群里讨论技术问题。

就在上个星期,在群里收到一个有关static的讨论,我个人觉得挺有意思的,于是打算将其整理成文,希望能够帮助大家更好地理解和应用static这个关键字。

群里的原问题如下:

大佬们,问一个比较低智问题,static修饰的变量不是只能被当前文件所调用吗?为什么这里在其他.c文件可以调用get_board_led_opr这个函数获取board_demo_led_opr这个变量的值。

03b5a3c4-312c-11ee-9e74-dac502259ad0.png

2 关于上述问题的答疑


这个问题群里也给出了一些参考答案,而我一开始的回答,并没有直接回答答案,而是随手提出了3个问题:

问自己几个问题:

1.get函数返回什么地址(各种地址)语法上有约束条款吗?

2.static修饰的全局变量存放在哪里?它的地址是什么样的?

3.c语言里面要想访问任意一个地址,从语法层面上,能阻止得了吗?

提问者的回答:

(1)get_board_led_opr函数返回的是一个自定义的结构体get_board_led_opr。但是get_board_led_opr这个结构体被static修饰了。(2)get_board_led_opr结构体放在了board_demo.c中,而调用get_board_led_opr函数是在leddrv.c中。
(3)我询问了另外一个群里面的大佬,他们说,static仅仅在编译期间有用。在运行状态是无效果的。也就是说,虽然leddrv.c无法直接使用get_board_led_opr这个结构体。但是可以利用get_board_led_opr函数,间接的获取get_board_led_opr这个结构体,因为get_board_led_opr函数和et_board_led_opr这个结构体在同一个.c文件中
上述问题的点关键在于理解两个:
  • 被static修饰之后,这个变量变成了什么?
  • C语言的万能指针。
​​首先,被static修饰之后,意味着只有 当前的C语言C文件 可以直接 引用访问它,但是并不代表外部的模块(除当前C文件外的其他C文件)就不能访问它。直接访问肯定是不行的,但是 间接 的方式肯定是可以的。它的方法就是如上图的代码片段那样,将static变量的地址,以指针的形式传出去给其他模块即可。这里还要理解的一点是,被static修饰的变量是存放在全局的数据区,它的有效生存空间是整一个C工程运行时间内都是有效的。所以你通过指针去访问它,就变成了可能;这也是我们学习指针时,提到的 间接访问 的最真实体验。

3 教科书里的static


乘此机会,我们来复习一下C语言教科书,对于static关键字,它们是怎么描述的?由于手头标准的教科书,已很难找了,索性问一下ChatGPT,看看它的总结:

在C语言中,static关键字有两种主要的用法:静态变量和静态函数。

1. 静态变量:

静态变量是在程序运行期间一直存在的变量,其生命周期从声明处到程序结束。静态变量被存储在静态数据区,不会受到函数的调用和返回的影响,每次进入函数都会保留上一次的值。静态变量可以在函数内部或者全局作用域中声明。在函数内部声明的静态变量只能在该函数内部访问,而在全局作用域中声明的静态变量可以在整个文件中访问。静态变量的主要作用:- 维护变量的持久状态,保持值的连续性。- 限制变量的作用域,只能在函数内或者文件内访问。- 避免与同名的全局变量产生冲突。示例代码:

void func()

{

static int count = 0; // 定义一个静态变量

count++;

printf(“Count: %d ”, count);

}

int main()

{

func(); // 输出:Count: 1

func(); // 输出:Count: 2

func(); // 输出:Count: 3

return 0;

}

2. 静态函数:

静态函数是只能在当前源文件中使用的函数,其作用于只限于声明所在的文件,无法被其他文件调用。使用static关键字修饰函数,可以实现函数的隐藏和封装。因此,静态函数的主要作用是限制函数的作用域,防止其他文件访问该函数,避免命名冲突,并且提高代码的可读性和可维护性。示例代码:

static void util_func(int value)

{

printf(“Value: %d ”, value);

}

int main()

{

util_func(10); // 可以在当前文件中调用util_func函数

return 0;

}

总结:static关键字在C语言中的用法主要有静态变量和静态函数。静态变量用于维护变量的持久状态和限制作用域,静态函数用于限制函数的作用域和提高代码的可读性。

基本从ChatGPT的总结,可以了解清楚static的使用;不过它上面未提及到的一点是:

在static修饰的静态变量中,有两种情况,一种是修饰全局的变量,叫静态全局变量;另一种是修饰局部变量,叫静态局部变量(其实如果从作用周期的时间来看,它也是全局的)。ChatGPT中演示的静态局部变量,它的作用域就仅限于定义变量的这个函数内(准确说是,定义变量的大括号范围内);一旦出了这个作用域,是没有办法访问到的。而静态全局变量,它的作用域又比静态局部变量更宽泛些,它可以允许定义静态全局变量的整个C文件内,都可以访问它;但是之外的,其他C文件是无法访问的。综上,static关键字,主要强调的是 静态的 这个含义,无非就是作用域的大小问题。 4 C语言的static究竟限制了谁?
从编译原理和编译流程来拆解这个,问题的答案就很快就能出来。我们就以第3小节中,ChatGPT给出的示例代码为例,深度拆解一下这个static。在正式拆解之前,需要具备一些前置知识:C语言的编译流程。曾经,我写过一篇相关的文章,大家可以提前参考下,一文带你了解C代码到底是如何被编译的在这里,我不打算一一搬过来,仅仅把一张图贴过来参考:

0480074a-312c-11ee-9e74-dac502259ad0.png

我们顺着这个思路来拆解跟踪一下代码里面的 static

  • 编写C代码(C源代码里面的static)


		

1main.c 2#include 3staticintg_count=0; 4voidfunc() 5{ 6staticintl_count=0;//定义一个静态局部变量 7l_count++; 8g_count++; 9printf("l_count:%d,g_count:%d ",l_count,g_count); 10} 11staticvoidutil_func(intvalue)//定义一个静态函数 12{ 13printf("Value:%d ",value); 14} 15externvoidtest_func(void); 16intmain() 17{ 18func();//输出:l_count:1 19func();//输出:l_count:2 20func();//输出:l_count:3 21util_func(10);//可以在当前文件中调用util_func函数,输出:Value: 10 22test_func();//调用test.c中的函数 23return0; 24}


		1test.c  2//假设它们都是可以访问的  3externintl_count;  4externintg_count;  5externvoidutil_func(intvalue);  6voidtest_func(void)  7{  8#if0  9l_count++;//访问l_count静态局部变量,编译报错 10g_count++;//访问g_count静态全局变量,编译报错 11util_func(100);//调用main.c中的static函数,编译报错 12#endif 13}

当test_func中的if-0打开后,根据我们上面的理论分析,肯定是编译不过的,如下:


		1test_static$gcc-otest*.c 2/usr/bin/ld:/tmp/ccawkyDR.o:infunction`test_func': 3test.c:(.text+0xa):undefinedreferenceto`l_count' 4/usr/bin/ld:test.c:(.text+0x13):undefinedreferenceto`l_count' 5/usr/bin/ld:test.c:(.text+0x19):undefinedreferenceto`g_count' 6/usr/bin/ld:test.c:(.text+0x22):undefinedreferenceto`g_count' 7/usr/bin/ld:test.c:(.text+0x2c):undefinedreferenceto`util_func' 8collect2:error:ldreturned1exitstatus

像这种就是很明显的找不到变量或函数的实现体,从而出现找不到引用的 链接 错误。

去掉这些引用后(if-0)打开,即可编译成功,且能够正常运行。


		

1test_static$gcc-otest*.c 2test_static$./test 3l_count:1,g_count:1 4l_count:2,g_count:2 5l_count:3,g_count:3 6Value:10

  • 分步拆解1:先看预处理后static的情况

使用的命令下:gcc -c -o main.o main.c -save-temps=obj

这时候我们可以看到 main.i main.s main.o 这几个文件。

先看main.i 的内容:


		1忽略前面对头文件内容的搬运  2#873"/usr/include/stdio.h"34  3#2"main.c"2  4#3"main.c"  5staticintg_count=0;  6voidfunc()  7{  8staticintl_count=0;  9l_count++; 10g_count++; 11printf("l_count:%d,g_count:%d ",l_count,g_count); 12} 13staticvoidutil_func(intvalue) 14{ 15printf("Value:%d ",value); 16} 17externvoidtest_func(void); 18intmain() 19{ 20func(); 21func(); 22func(); 23util_func(10); 24test_func(); 25return0;

从上基本可以看到,static还是在的,并且整一个预处理后的代码,基本保留了源代码的样子(原因是我们并没有使用类似宏定义的内容)。

  • 拆解第2步:看看汇编文件有没有static的影子

这时候我们要查看的是 main.s 文件:


		1test_static$catmain.s  2.file"main.c"  3.text  4.localg_count  5.commg_count,4,4  6.section.rodata  7.LC0:  8.string"l_count:%d,g_count:%d "  9.text  10.globlfunc  11.typefunc,@function  12func:  13.LFB0:  14.cfi_startproc  15endbr64  16pushq%rbp  17.cfi_def_cfa_offset16  18.cfi_offset6,-16  19movq%rsp,%rbp  20.cfi_def_cfa_register6  21movll_count.2316(%rip),%eax  22addl$1,%eax  23movl%eax,l_count.2316(%rip)  24movlg_count(%rip),%eax  25addl$1,%eax  26movl%eax,g_count(%rip)  27movlg_count(%rip),%edx  28movll_count.2316(%rip),%eax  29movl%eax,%esi  30leaq.LC0(%rip),%rdi  31movl$0,%eax  32callprintf@PLT  33nop  34popq%rbp  35.cfi_def_cfa7,8  36ret  37.cfi_endproc  38.LFE0:  39.sizefunc,.-func  40.section.rodata  41.LC1:  42.string"Value:%d "  43.text  44.typeutil_func,@function  45util_func:  46.LFB1:  47.cfi_startproc  48endbr64  49pushq%rbp  50.cfi_def_cfa_offset16  51.cfi_offset6,-16  52movq%rsp,%rbp  53.cfi_def_cfa_register6  54subq$16,%rsp  55movl%edi,-4(%rbp)  56movl-4(%rbp),%eax  57movl%eax,%esi  58leaq.LC1(%rip),%rdi  59movl$0,%eax  60callprintf@PLT  61nop  62leave  63.cfi_def_cfa7,8  64ret  65.cfi_endproc  66.LFE1:  67.sizeutil_func,.-util_func  68.globlmain  69.typemain,@function  70main:  71.LFB2:  72.cfi_startproc  73endbr64  74pushq%rbp  75.cfi_def_cfa_offset16  76.cfi_offset6,-16  77movq%rsp,%rbp  78.cfi_def_cfa_register6  79movl$0,%eax  80callfunc  81movl$0,%eax  82callfunc  83movl$0,%eax  84callfunc  85movl$10,%edi  86callutil_func  87calltest_func@PLT  88movl$0,%eax  89popq%rbp  90.cfi_def_cfa7,8  91ret  92.cfi_endproc  93.LFE2:  94.sizemain,.-main  95.locall_count.2316  96.comml_count.2316,4,4  97.ident"GCC:(Ubuntu9.4.0-1ubuntu1~20.04.1)9.4.0"  98.section.note.GNU-stack,"",@progbits  99.section.note.gnu.property,"a" 100.align8 101.long1f-0f 102.long4f-1f 103.long5 1040: 105.string"GNU" 1061: 107.align8 108.long0xc0000002 109.long3f-2f 1102: 111.long0x3 1123: 113.align8 1144:

初一打开,可能有种不太认识的感觉,没关系,我们先找到我们能认识的东西。

先找到被static修饰过的内容(静态全局变量、静态局部变量、静态函数)。

1)静态全局变量g_count:


		

1.file"main.c" 2.text 3.localg_count 4.commg_count,4,4 5.section.rodata

2)静态局部变量l_count:


		1.LFE2: 2.sizemain,.-main 3.locall_count.2316 4.comml_count.2316,4,4

3)静态函数util_func:


		1.string"Value:%d "  2.text  3.typeutil_func,@function  4util_func:  5.LFB1:  6.cfi_startproc  7endbr64  8pushq%rbp  9.cfi_def_cfa_offset16 10.cfi_offset6,-16 11movq%rsp,%rbp 12.cfi_def_cfa_register6 13subq$16,%rsp 14movl%edi,-4(%rbp) 15movl-4(%rbp),%eax 16movl%eax,%esi 17leaq.LC1(%rip),%rdi 18movl$0,%eax 19callprintf@PLT 20nop 21leave 22.cfi_def_cfa7,8 23ret 24.cfi_endproc

由于我们只是对main.c进行汇编,所以看不出全貌,但是能够确认的是,在汇编文件中,static已经消失了,换句话说,接下来就没static啥事情了,而是转为其他信息了。我们接着往下拆解。

  • 拆解第3步:obj文件里面确认没有static的要素吗?

我们看下main.o文件,由于它不是可读文件,所以得用其他指令分析下:


		

1test_static$readelf-amain.o 2ELFHeader: 3Magic:7f454c46020101000000000000000000 4Class:ELF64 5Data:2'scomplement,littleendian 6Version:1(current) 7OS/ABI:UNIX-SystemV 8ABIVersion:0 9Type:REL(Relocatablefile) 10Machine:AdvancedMicroDevicesX86-64 11Version:0x1 12Entrypointaddress:0x0 13Startofprogramheaders:0(bytesintofile) 14Startofsectionheaders:1520(bytesintofile) 15Flags:0x0 16Sizeofthisheader:64(bytes) 17Sizeofprogramheaders:0(bytes) 18Numberofprogramheaders:0 19Sizeofsectionheaders:64(bytes) 20Numberofsectionheaders:14 21Sectionheaderstringtableindex:13 22SectionHeaders: 23[Nr]NameTypeAddressOffset 24SizeEntSizeFlagsLinkInfoAlign 25[0]NULL000000000000000000000000 2600000000000000000000000000000000000 27[1].textPROGBITS000000000000000000000040 2800000000000000ac0000000000000000AX001 29[2].rela.textRELA0000000000000000000003e0 3000000000000001500000000000000018I1118 31[3].dataPROGBITS0000000000000000000000ec 3200000000000000000000000000000000WA001 33[4].bssNOBITS0000000000000000000000ec 3400000000000000080000000000000000WA004 35[5].rodataPROGBITS0000000000000000000000ec 3600000000000000250000000000000000A001 37[6].commentPROGBITS000000000000000000000111 38000000000000002c0000000000000001MS001 39[7].note.GNU-stackPROGBITS00000000000000000000013d 4000000000000000000000000000000000001 41[8].note.gnu.propertNOTE000000000000000000000140 4200000000000000200000000000000000A008 43[9].eh_framePROGBITS000000000000000000000160 4400000000000000780000000000000000A008 45[10].rela.eh_frameRELA000000000000000000000530 4600000000000000480000000000000018I1198 47[11].symtabSYMTAB0000000000000000000001d8 4800000000000001b0000000000000001812138 49[12].strtabSTRTAB000000000000000000000388 5000000000000000530000000000000000001 51[13].shstrtabSTRTAB000000000000000000000578 5200000000000000740000000000000000001 53KeytoFlags: 54W(write),A(alloc),X(execute),M(merge),S(strings),I(info), 55L(linkorder),O(extraOSprocessingrequired),G(group),T(TLS), 56C(compressed),x(unknown),o(OSspecific),E(exclude), 57l(large),p(processorspecific) 58Therearenosectiongroupsinthisfile. 59Therearenoprogramheadersinthisfile. 60Thereisnodynamicsectioninthisfile. 61Relocationsection'.rela.text'atoffset0x3e0contains14entries: 62OffsetInfoTypeSym.ValueSym.Name+Addend 6300000000000a000400000002R_X86_64_PC320000000000000000.bss+0 64000000000013000400000002R_X86_64_PC320000000000000000.bss+0 65000000000019000400000002R_X86_64_PC320000000000000000.bss-4 66000000000022000400000002R_X86_64_PC320000000000000000.bss-4 67000000000028000400000002R_X86_64_PC320000000000000000.bss-4 6800000000002e000400000002R_X86_64_PC320000000000000000.bss+0 69000000000037000600000002R_X86_64_PC320000000000000000.rodata-4 70000000000041000f00000004R_X86_64_PLT320000000000000000printf-4 7100000000005f000600000002R_X86_64_PC320000000000000000.rodata+16 72000000000069000f00000004R_X86_64_PLT320000000000000000printf-4 7300000000007e000d00000004R_X86_64_PLT320000000000000000func-4 74000000000088000d00000004R_X86_64_PLT320000000000000000func-4 75000000000092000d00000004R_X86_64_PLT320000000000000000func-4 760000000000a1001100000004R_X86_64_PLT320000000000000000test_func-4 77Relocationsection'.rela.eh_frame'atoffset0x530contains3entries: 78OffsetInfoTypeSym.ValueSym.Name+Addend 79000000000020000200000002R_X86_64_PC320000000000000000.text+0 80000000000040000200000002R_X86_64_PC320000000000000000.text+48 81000000000060000200000002R_X86_64_PC320000000000000000.text+70 82ThedecodingofunwindsectionsformachinetypeAdvancedMicroDevicesX86-64isnotcurrentlysupported. 83Symboltable'.symtab'contains18entries: 84Num:ValueSizeTypeBindVisNdxName 850:00000000000000000NOTYPELOCALDEFAULTUND 861:00000000000000000FILELOCALDEFAULTABSmain.c 872:00000000000000000SECTIONLOCALDEFAULT1 883:00000000000000000SECTIONLOCALDEFAULT3 894:00000000000000000SECTIONLOCALDEFAULT4 905:00000000000000004OBJECTLOCALDEFAULT4g_count 916:00000000000000000SECTIONLOCALDEFAULT5 927:00000000000000044OBJECTLOCALDEFAULT4l_count.2316 938:000000000000004840FUNCLOCALDEFAULT1util_func 949:00000000000000000SECTIONLOCALDEFAULT7 9510:00000000000000000SECTIONLOCALDEFAULT8 9611:00000000000000000SECTIONLOCALDEFAULT9 9712:00000000000000000SECTIONLOCALDEFAULT6 9813:000000000000000072FUNCGLOBALDEFAULT1func 9914:00000000000000000NOTYPEGLOBALDEFAULTUND_GLOBAL_OFFSET_TABLE_ 10015:00000000000000000NOTYPEGLOBALDEFAULTUNDprintf 10116:000000000000007060FUNCGLOBALDEFAULT1main 10217:00000000000000000NOTYPEGLOBALDEFAULTUNDtest_func 103Noversioninformationfoundinthisfile. 104Displayingnotesfoundin:.note.gnu.property 105OwnerDatasizeDescription 106GNU0x00000010NT_GNU_PROPERTY_TYPE_0 107Properties:x86feature:IBT,SHSTK 108recan@ubuntu:~/win_share_workspace/test_share/test_static$

从上面可以看到,g_count、l_count、util_func 都被 LOCAL 修饰了,而非 GLOBAL 的:

		15:00000000000000004OBJECTLOCALDEFAULT4g_count 26:00000000000000000SECTIONLOCALDEFAULT5 37:00000000000000044OBJECTLOCALDEFAULT4l_count.2316 48:000000000000004840FUNCLOCALDEFAULT1util_func 

究竟这两者修饰有啥区别,会产生什么影响呢?我们接着往下拆解。

  • 拆解第4步:链接后的可执行文件反汇编

前面也说到了,由于我们都只看到 main这个C文件相关 预处理、汇编、obj内容,而没有看到整个可执行文件的全貌。

执行反汇编看看:


		1test_static$objdump-l-d-x-s-Stest  2test:fileformatelf64-x86-64  3test  4architecture:i386:x86-64,flags0x00000150:  5HAS_SYMS,DYNAMIC,D_PAGED  6startaddress0x0000000000001060  7ProgramHeader:  8PHDRoff0x0000000000000040vaddr0x0000000000000040paddr0x0000000000000040align2**3  9filesz0x00000000000002d8memsz0x00000000000002d8flagsr--  10INTERPoff0x0000000000000318vaddr0x0000000000000318paddr0x0000000000000318align2**0  11filesz0x000000000000001cmemsz0x000000000000001cflagsr--  12LOADoff0x0000000000000000vaddr0x0000000000000000paddr0x0000000000000000align2**12  13filesz0x0000000000000600memsz0x0000000000000600flagsr--  14LOADoff0x0000000000001000vaddr0x0000000000001000paddr0x0000000000001000align2**12  15filesz0x0000000000000285memsz0x0000000000000285flagsr-x  16LOADoff0x0000000000002000vaddr0x0000000000002000paddr0x0000000000002000align2**12  17filesz0x00000000000001f0memsz0x00000000000001f0flagsr--  18LOADoff0x0000000000002db8vaddr0x0000000000003db8paddr0x0000000000003db8align2**12  19filesz0x0000000000000258memsz0x0000000000000268flagsrw-  20DYNAMICoff0x0000000000002dc8vaddr0x0000000000003dc8paddr0x0000000000003dc8align2**3  21filesz0x00000000000001f0memsz0x00000000000001f0flagsrw-  22NOTEoff0x0000000000000338vaddr0x0000000000000338paddr0x0000000000000338align2**3  23filesz0x0000000000000020memsz0x0000000000000020flagsr--  24NOTEoff0x0000000000000358vaddr0x0000000000000358paddr0x0000000000000358align2**2  25filesz0x0000000000000044memsz0x0000000000000044flagsr--  260x6474e553off0x0000000000000338vaddr0x0000000000000338paddr0x0000000000000338align2**3  27filesz0x0000000000000020memsz0x0000000000000020flagsr--  28EH_FRAMEoff0x000000000000202cvaddr0x000000000000202cpaddr0x000000000000202calign2**2  29filesz0x000000000000005cmemsz0x000000000000005cflagsr--  30STACKoff0x0000000000000000vaddr0x0000000000000000paddr0x0000000000000000align2**4  31filesz0x0000000000000000memsz0x0000000000000000flagsrw-  32RELROoff0x0000000000002db8vaddr0x0000000000003db8paddr0x0000000000003db8align2**0  33filesz0x0000000000000248memsz0x0000000000000248flagsr--  34DynamicSection:  35NEEDEDlibc.so.6  36INIT0x0000000000001000  37FINI0x0000000000001278  38INIT_ARRAY0x0000000000003db8  39INIT_ARRAYSZ0x0000000000000008  40FINI_ARRAY0x0000000000003dc0  41FINI_ARRAYSZ0x0000000000000008  42GNU_HASH0x00000000000003a0  43STRTAB0x0000000000000470  44SYMTAB0x00000000000003c8  45STRSZ0x0000000000000084  46SYMENT0x0000000000000018  47DEBUG0x0000000000000000  48PLTGOT0x0000000000003fb8  49PLTRELSZ0x0000000000000018  50PLTREL0x0000000000000007  51JMPREL0x00000000000005e8  52RELA0x0000000000000528  53RELASZ0x00000000000000c0  54RELAENT0x0000000000000018  55FLAGS0x0000000000000008  56FLAGS_10x0000000008000001  57VERNEED0x0000000000000508  58VERNEEDNUM0x0000000000000001  59VERSYM0x00000000000004f4  60RELACOUNT0x0000000000000003  61VersionReferences:  62requiredfromlibc.so.6:  630x09691a750x0002GLIBC_2.2.5  64Sections:  65IdxNameSizeVMALMAFileoffAlgn  660.interp0000001c00000000000003180000000000000318000003182**0  67CONTENTS,ALLOC,LOAD,READONLY,DATA  681.note.gnu.property0000002000000000000003380000000000000338000003382**3  69CONTENTS,ALLOC,LOAD,READONLY,DATA  702.note.gnu.build-id0000002400000000000003580000000000000358000003582**2  71CONTENTS,ALLOC,LOAD,READONLY,DATA  723.note.ABI-tag00000020000000000000037c000000000000037c0000037c2**2  73CONTENTS,ALLOC,LOAD,READONLY,DATA  744.gnu.hash0000002400000000000003a000000000000003a0000003a02**3  75CONTENTS,ALLOC,LOAD,READONLY,DATA  765.dynsym000000a800000000000003c800000000000003c8000003c82**3  77CONTENTS,ALLOC,LOAD,READONLY,DATA  786.dynstr0000008400000000000004700000000000000470000004702**0  79CONTENTS,ALLOC,LOAD,READONLY,DATA  807.gnu.version0000000e00000000000004f400000000000004f4000004f42**1  81CONTENTS,ALLOC,LOAD,READONLY,DATA  828.gnu.version_r0000002000000000000005080000000000000508000005082**3  83CONTENTS,ALLOC,LOAD,READONLY,DATA  849.rela.dyn000000c000000000000005280000000000000528000005282**3  85CONTENTS,ALLOC,LOAD,READONLY,DATA  8610.rela.plt0000001800000000000005e800000000000005e8000005e82**3  87CONTENTS,ALLOC,LOAD,READONLY,DATA  8811.init0000001b00000000000010000000000000001000000010002**2  89CONTENTS,ALLOC,LOAD,READONLY,CODE  9012.plt0000002000000000000010200000000000001020000010202**4  91CONTENTS,ALLOC,LOAD,READONLY,CODE  9213.plt.got0000001000000000000010400000000000001040000010402**4  93CONTENTS,ALLOC,LOAD,READONLY,CODE  9414.plt.sec0000001000000000000010500000000000001050000010502**4  95CONTENTS,ALLOC,LOAD,READONLY,CODE  9615.text0000021500000000000010600000000000001060000010602**4  97CONTENTS,ALLOC,LOAD,READONLY,CODE  9816.fini0000000d00000000000012780000000000001278000012782**2  99CONTENTS,ALLOC,LOAD,READONLY,CODE 10017.rodata0000002900000000000020000000000000002000000020002**2 101CONTENTS,ALLOC,LOAD,READONLY,DATA 10218.eh_frame_hdr0000005c000000000000202c000000000000202c0000202c2**2 103CONTENTS,ALLOC,LOAD,READONLY,DATA 10419.eh_frame0000016800000000000020880000000000002088000020882**3 105CONTENTS,ALLOC,LOAD,READONLY,DATA 10620.init_array000000080000000000003db80000000000003db800002db82**3 107CONTENTS,ALLOC,LOAD,DATA 10821.fini_array000000080000000000003dc00000000000003dc000002dc02**3 109CONTENTS,ALLOC,LOAD,DATA 11022.dynamic000001f00000000000003dc80000000000003dc800002dc82**3 111CONTENTS,ALLOC,LOAD,DATA 11223.got000000480000000000003fb80000000000003fb800002fb82**3 113CONTENTS,ALLOC,LOAD,DATA 11424.data0000001000000000000040000000000000004000000030002**3 115CONTENTS,ALLOC,LOAD,DATA 11625.bss0000001000000000000040100000000000004010000030102**2 117ALLOC 11826.comment0000002b00000000000000000000000000000000000030102**0 119CONTENTS,READONLY 120SYMBOLTABLE: 1210000000000000318ld.interp0000000000000000.interp 1220000000000000338ld.note.gnu.property0000000000000000.note.gnu.property 1230000000000000358ld.note.gnu.build-id0000000000000000.note.gnu.build-id 124000000000000037cld.note.ABI-tag0000000000000000.note.ABI-tag 12500000000000003a0ld.gnu.hash0000000000000000.gnu.hash 12600000000000003c8ld.dynsym0000000000000000.dynsym 1270000000000000470ld.dynstr0000000000000000.dynstr 12800000000000004f4ld.gnu.version0000000000000000.gnu.version 1290000000000000508ld.gnu.version_r0000000000000000.gnu.version_r 1300000000000000528ld.rela.dyn0000000000000000.rela.dyn 13100000000000005e8ld.rela.plt0000000000000000.rela.plt 1320000000000001000ld.init0000000000000000.init 1330000000000001020ld.plt0000000000000000.plt 1340000000000001040ld.plt.got0000000000000000.plt.got 1350000000000001050ld.plt.sec0000000000000000.plt.sec 1360000000000001060ld.text0000000000000000.text 1370000000000001278ld.fini0000000000000000.fini 1380000000000002000ld.rodata0000000000000000.rodata 139000000000000202cld.eh_frame_hdr0000000000000000.eh_frame_hdr 1400000000000002088ld.eh_frame0000000000000000.eh_frame 1410000000000003db8ld.init_array0000000000000000.init_array 1420000000000003dc0ld.fini_array0000000000000000.fini_array 1430000000000003dc8ld.dynamic0000000000000000.dynamic 1440000000000003fb8ld.got0000000000000000.got 1450000000000004000ld.data0000000000000000.data 1460000000000004010ld.bss0000000000000000.bss 1470000000000000000ld.comment0000000000000000.comment 1480000000000000000ldf*ABS*0000000000000000crtstuff.c 1490000000000001090lF.text0000000000000000deregister_tm_clones 15000000000000010c0lF.text0000000000000000register_tm_clones 1510000000000001100lF.text0000000000000000__do_global_dtors_aux 1520000000000004010lO.bss0000000000000001completed.8061 1530000000000003dc0lO.fini_array0000000000000000__do_global_dtors_aux_fini_array_entry 1540000000000001140lF.text0000000000000000frame_dummy 1550000000000003db8lO.init_array0000000000000000__frame_dummy_init_array_entry 1560000000000000000ldf*ABS*0000000000000000main.c 1570000000000004014lO.bss0000000000000004g_count 1580000000000004018lO.bss0000000000000004l_count.2316 1590000000000001191lF.text0000000000000028util_func 1600000000000000000ldf*ABS*0000000000000000test.c 1610000000000000000ldf*ABS*0000000000000000crtstuff.c 16200000000000021eclO.eh_frame0000000000000000__FRAME_END__ 1630000000000000000ldf*ABS*0000000000000000 1640000000000003dc0l.init_array0000000000000000__init_array_end 1650000000000003dc8lO.dynamic0000000000000000_DYNAMIC 1660000000000003db8l.init_array0000000000000000__init_array_start 167000000000000202cl.eh_frame_hdr0000000000000000__GNU_EH_FRAME_HDR 1680000000000003fb8lO.got0000000000000000_GLOBAL_OFFSET_TABLE_ 1690000000000001000lF.init0000000000000000_init 1700000000000001270gF.text0000000000000005__libc_csu_fini 1710000000000000000w*UND*0000000000000000_ITM_deregisterTMCloneTable 1720000000000004000w.data0000000000000000data_start 1730000000000004010g.data0000000000000000_edata 1740000000000001278gF.fini0000000000000000.hidden_fini 1750000000000000000F*UND*0000000000000000printf@@GLIBC_2.2.5 17600000000000011f5gF.text000000000000000btest_func 1770000000000000000F*UND*0000000000000000__libc_start_main@@GLIBC_2.2.5 1780000000000004000g.data0000000000000000__data_start 1790000000000000000w*UND*0000000000000000__gmon_start__ 1800000000000004008gO.data0000000000000000.hidden__dso_handle 1810000000000002000gO.rodata0000000000000004_IO_stdin_used 1820000000000001149gF.text0000000000000048func 1830000000000001200gF.text0000000000000065__libc_csu_init 1840000000000004020g.bss0000000000000000_end 1850000000000001060gF.text000000000000002f_start 1860000000000004010g.bss0000000000000000__bss_start 18700000000000011b9gF.text000000000000003cmain 1880000000000004010gO.data0000000000000000.hidden__TMC_END__ 1890000000000000000w*UND*0000000000000000_ITM_registerTMCloneTable 1900000000000000000wF*UND*0000000000000000__cxa_finalize@@GLIBC_2.2.5 191Contentsofsection.interp: 19203182f6c696236342f6c642d6c696e75782d/lib64/ld-linux- 19303287838362d36342e736f2e3200x86-64.so.2. 194省略了一些无关紧要的内容 195Contentsofsection.data: 196400000000000000000000840000000000000.........@...... 197Contentsofsection.comment: 19800004743433a20285562756e747520392e34GCC:(Ubuntu9.4 19900102e302d317562756e7475317e32302e30.0-1ubuntu1~20.0 2000020342e312920392e342e30004.1)9.4.0. 201Disassemblyofsection.init: 2020000000000001000<_init>: 203_init(): 2041000:f30f1efaendbr64 2051004:4883ec08sub$0x8,%rsp 2061008:488b05d92f0000mov0x2fd9(%rip),%rax#3fe8<__gmon_start__> 207100f:4885c0test%rax,%rax 2081012:7402je1016<_init+0x16> 2091014:ffd0callq*%rax 2101016:4883c408add$0x8,%rsp 211101a:c3retq 212Disassemblyofsection.plt: 2130000000000001020<.plt>: 2141020:ff359a2f0000pushq0x2f9a(%rip)#3fc0<_GLOBAL_OFFSET_TABLE_+0x8> 2151026:f2ff259b2f0000bndjmpq*0x2f9b(%rip)#3fc8<_GLOBAL_OFFSET_TABLE_+0x10> 216102d:0f1f00nopl(%rax) 2171030:f30f1efaendbr64 2181034:6800000000pushq$0x0 2191039:f2e9e1ffffffbndjmpq1020<.plt> 220103f:90nop 221Disassemblyofsection.plt.got: 2220000000000001040<__cxa_finalize@plt>: 2231040:f30f1efaendbr64 2241044:f2ff25ad2f0000bndjmpq*0x2fad(%rip)#3ff8<__cxa_finalize@GLIBC_2.2.5> 225104b:0f1f440000nopl0x0(%rax,%rax,1) 226Disassemblyofsection.plt.sec: 2270000000000001050: 2281050:f30f1efaendbr64 2291054:f2ff25752f0000bndjmpq*0x2f75(%rip)#3fd0@glibc_2.2.5> 230105b:0f1f440000nopl0x0(%rax,%rax,1) 231Disassemblyofsection.text: 2320000000000001060<_start>: 233_start(): 2341060:f30f1efaendbr64 2351064:31edxor%ebp,%ebp 2361066:4989d1mov%rdx,%r9 2371069:5epop%rsi 238106a:4889e2mov%rsp,%rdx 239106d:4883e4f0and$0xfffffffffffffff0,%rsp 2401071:50push%rax 2411072:54push%rsp 2421073:4c8d05f6010000lea0x1f6(%rip),%r8#1270<__libc_csu_fini> 243107a:488d0d7f010000lea0x17f(%rip),%rcx#1200<__libc_csu_init> 2441081:488d3d31010000lea0x131(%rip),%rdi#11b92451088:ff15522f0000callq*0x2f52(%rip)#3fe0<__libc_start_main@GLIBC_2.2.5> 246108e:f4hlt 247108f:90nop 2480000000000001090: 249deregister_tm_clones(): 2501090:488d3d792f0000lea0x2f79(%rip),%rdi#4010<__TMC_END__> 2511097:488d05722f0000lea0x2f72(%rip),%rax#4010<__TMC_END__> 252109e:4839f8cmp%rdi,%rax 25310a1:7415je10b80x28> 25410a3:488b052e2f0000mov0x2f2e(%rip),%rax#3fd8<_ITM_deregisterTMCloneTable> 25510aa:4885c0test%rax,%rax 25610ad:7409je10b80x28> 25710af:ffe0jmpq*%rax 25810b1:0f1f8000000000nopl0x0(%rax) 25910b8:c3retq 26010b9:0f1f8000000000nopl0x0(%rax) 26100000000000010c0: 262register_tm_clones(): 26310c0:488d3d492f0000lea0x2f49(%rip),%rdi#4010<__TMC_END__> 26410c7:488d35422f0000lea0x2f42(%rip),%rsi#4010<__TMC_END__> 26510ce:4829fesub%rdi,%rsi 26610d1:4889f0mov%rsi,%rax 26710d4:48c1ee3fshr$0x3f,%rsi 26810d8:48c1f803sar$0x3,%rax 26910dc:4801c6add%rax,%rsi 27010df:48d1fesar%rsi 27110e2:7414je10f80x38> 27210e4:488b05052f0000mov0x2f05(%rip),%rax#3ff0<_ITM_registerTMCloneTable> 27310eb:4885c0test%rax,%rax 27410ee:7408je10f80x38> 27510f0:ffe0jmpq*%rax 27610f2:660f1f440000nopw0x0(%rax,%rax,1) 27710f8:c3retq 27810f9:0f1f8000000000nopl0x0(%rax) 2790000000000001100<__do_global_dtors_aux>: 280__do_global_dtors_aux(): 2811100:f30f1efaendbr64 2821104:803d052f000000cmpb$0x0,0x2f05(%rip)#4010<__TMC_END__> 283110b:752bjne1138<__do_global_dtors_aux+0x38> 284110d:55push%rbp 285110e:48833de22e0000cmpq$0x0,0x2ee2(%rip)#3ff8<__cxa_finalize@GLIBC_2.2.5> 2861115:00 2871116:4889e5mov%rsp,%rbp 2881119:740cje1127<__do_global_dtors_aux+0x27> 289111b:488b3de62e0000mov0x2ee6(%rip),%rdi#4008<__dso_handle> 2901122:e819ffffffcallq1040<__cxa_finalize@plt> 2911127:e864ffffffcallq1090292112c:c605dd2e000001movb$0x1,0x2edd(%rip)#4010<__TMC_END__> 2931133:5dpop%rbp 2941134:c3retq 2951135:0f1f00nopl(%rax) 2961138:c3retq 2971139:0f1f8000000000nopl0x0(%rax) 2980000000000001140: 299frame_dummy(): 3001140:f30f1efaendbr64 3011144:e977ffffffjmpq10c03020000000000001149: 303func(): 3041149:f30f1efaendbr64 305114d:55push%rbp 306114e:4889e5mov%rsp,%rbp 3071151:8b05c12e0000mov0x2ec1(%rip),%eax#4018 3081157:83c001add$0x1,%eax 309115a:8905b82e0000mov%eax,0x2eb8(%rip)#4018 3101160:8b05ae2e0000mov0x2eae(%rip),%eax#4014 3111166:83c001add$0x1,%eax 3121169:8905a52e0000mov%eax,0x2ea5(%rip)#4014 313116f:8b159f2e0000mov0x2e9f(%rip),%edx#4014 3141175:8b059d2e0000mov0x2e9d(%rip),%eax#4018 315117b:89c6mov%eax,%esi 316117d:488d3d800e0000lea0xe80(%rip),%rdi#2004<_IO_stdin_used+0x4> 3171184:b800000000mov$0x0,%eax 3181189:e8c2feffffcallq1050319118e:90nop 320118f:5dpop%rbp 3211190:c3retq 3220000000000001191: 323util_func(): 3241191:f30f1efaendbr64 3251195:55push%rbp 3261196:4889e5mov%rsp,%rbp 3271199:4883ec10sub$0x10,%rsp 328119d:897dfcmov%edi,-0x4(%rbp) 32911a0:8b45fcmov-0x4(%rbp),%eax 33011a3:89c6mov%eax,%esi 33111a5:488d3d720e0000lea0xe72(%rip),%rdi#201e<_IO_stdin_used+0x1e> 33211ac:b800000000mov$0x0,%eax 33311b1:e89afeffffcallq105033411b6:90nop 33511b7:c9leaveq 33611b8:c3retq 33700000000000011b9<main>: 338main(): 33911b9:f30f1efaendbr64 34011bd:55push%rbp 34111be:4889e5mov%rsp,%rbp 34211c1:b800000000mov$0x0,%eax 34311c6:e87effffffcallq114934411cb:b800000000mov$0x0,%eax 34511d0:e874ffffffcallq114934611d5:b800000000mov$0x0,%eax 34711da:e86affffffcallq114934811df:bf0a000000mov$0xa,%edi 34911e4:e8a8ffffffcallq119135011e9:e807000000callq11f535111ee:b800000000mov$0x0,%eax 35211f3:5dpop%rbp 35311f4:c3retq 35400000000000011f5: 355test_func(): 35611f5:f30f1efaendbr64 35711f9:55push%rbp 35811fa:4889e5mov%rsp,%rbp 35911fd:90nop 36011fe:5dpop%rbp 36111ff:c3retq 3620000000000001200<__libc_csu_init>: 363__libc_csu_init(): 3641200:f30f1efaendbr64 3651204:4157push%r15 3661206:4c8d3dab2b0000lea0x2bab(%rip),%r15#3db8<__frame_dummy_init_array_entry> 367120d:4156push%r14 368120f:4989d6mov%rdx,%r14 3691212:4155push%r13 3701214:4989f5mov%rsi,%r13 3711217:4154push%r12 3721219:4189fcmov%edi,%r12d 373121c:55push%rbp 374121d:488d2d9c2b0000lea0x2b9c(%rip),%rbp#3dc0<__do_global_dtors_aux_fini_array_entry> 3751224:53push%rbx 3761225:4c29fdsub%r15,%rbp 3771228:4883ec08sub$0x8,%rsp 378122c:e8cffdffffcallq1000<_init> 3791231:48c1fd03sar$0x3,%rbp 3801235:741fje1256<__libc_csu_init+0x56> 3811237:31dbxor%ebx,%ebx 3821239:0f1f8000000000nopl0x0(%rax) 3831240:4c89f2mov%r14,%rdx 3841243:4c89eemov%r13,%rsi 3851246:4489e7mov%r12d,%edi 3861249:41ff14dfcallq*(%r15,%rbx,8) 387124d:4883c301add$0x1,%rbx 3881251:4839ddcmp%rbx,%rbp 3891254:75eajne1240<__libc_csu_init+0x40> 3901256:4883c408add$0x8,%rsp 391125a:5bpop%rbx 392125b:5dpop%rbp 393125c:415cpop%r12 394125e:415dpop%r13 3951260:415epop%r14 3961262:415fpop%r15 3971264:c3retq 3981265:66662e0f1f8400data16nopw%cs:0x0(%rax,%rax,1) 399126c:00000000 4000000000000001270<__libc_csu_fini>: 401__libc_csu_fini(): 4021270:f30f1efaendbr64 4031274:c3retq 404Disassemblyofsection.fini: 4050000000000001278<_fini>: 406_fini(): 4071278:f30f1efaendbr64 408127c:4883ec08sub$0x8,%rsp 4091280:4883c408add$0x8,%rsp 4101284:c3retq @plt>@plt>++++@plt>老规矩,看不懂全部不重要,找你能看得懂的。还是找到 l_count 、g_count、util_test 这几个来吧。04a8ea3e-312c-11ee-9e74-dac502259ad0.png看样子也没啥特殊的,所以问题的关键还在前一步:链接器那里。综上可知,static的修饰主要是给编译器做了提示,从而生成的obj文件中带了 local属性,这样就告诉链接器,不能扩大这些被local修饰过的内容的使用范围,从而达到了教科书上面说的那样static的作用效果。其实还有一个方法,就是你写一个带static和不带static的,比如都是全局变量的两个,通过反汇编来对比分析,这样也可以快速看出核心区别,就留给读者去探索吧。再留一个疑问:编译器、链接器 如何做到一个static修饰的局部变量,只能被定义的当前函数内访问的?这个问题,有点深入,也留给读者去探索吧。
		5 一种绕开static限制的方法
谈到绕开static的限制,其实本文第1小节的那个问题例子就是一个很好的思路和方法。要想绕开static的限制,无非就是:将被static修饰的函数转换为没有被static修饰的函数!或者将被static修饰的变量转换为没有被static修饰的变量!这个做法,还有一个行业名词叫:封装在第1小节中,代码中演示的是将被static修饰的变量,通过传出其地址,以指针的形式导出给外部模块使用。下面的代码片段,将展示将被static修饰的函数,转换为没有被static修饰的函数,从而给外部模块使用。

		1test_a.c  2staticinttest_func_in_a(inta)  3{  4returna+1;  5}  6inttest_func_in_a_ex(inta)  7{  8returntest_func_in_a(a);  9} 10---------------------------- 11test_b.c 12inttest_func_in_b(void) 13{ 14inta=1; 15intb; 16//calltest_func_in_afunctionfailbecauseof"static" 17//b=test_func_in_a(a) 18//calltest_func_in_a_exfunctionokwithout"static" 19b=test_func_in_a_ex(a) 20returnb; 21}示例代码很简单,仅仅就是在_test_a.c 中,编写一个不被static修饰的函数 test_func_in_a_ex,然后它去调用被static修饰的test_func_in_a函数,这样就轻松绕开了static的限制。你学会了吗?
		6 拓展延伸:如何调用静态库里的被static修饰的函数?
关于这个扩展延伸,其实我很早就起草了一篇博文想写这个内容来着,但是一直拖,一直拖,直到现在还没生产。索性就在本文做个牵引吧!个人认为,对于此问题,应该分为两个场景:静态库的代码,你有修改的权限;或者你能找到人来修改;比如,公司内部不同团队直接的公有库代码;静态库的代码,你完全没办法查看源码或修改源码;比如一些第三方的库。针对这两种不同的场景,可能采取的方式是不一样的,你觉得应该如何做最好呢?如果你也对此问题感兴趣,请关注我的后续的拆解博文。

原文:https://club.rt-thread.org/ask/article/1b38085300b58f82.html

作者:recan

———————End——————


点击阅读原文进入官网

​​​​​​


原文标题:【知识科普】C语言的static究竟限制了谁

文章出处:【微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。


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

    关注

    31

    文章

    1286

    浏览量

    40110

原文标题:【知识科普】C语言的static究竟限制了谁

文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言与Java语言的对比

    C语言和Java语言都是当前编程领域中的重要成员,它们各自具有独特的优势和特点,适用于不同的应用场景。以下将从语法特性、内存管理、跨平台性、性能、应用领域等多个方面对C
    的头像 发表于 10-29 17:31 322次阅读

    技术干货驿站 ▏深入理解C语言:掌握程序结构知识

    在计算机编程的世界中,C语言被广泛认可为一门强大而高效的编程语言,其简洁的语法和直接的指令使得它成为了许多程序员的首选。了解C语言的程序结构
    的头像 发表于 07-27 08:45 1369次阅读
    技术干货驿站 ▏深入理解<b class='flag-5'>C</b><b class='flag-5'>语言</b>:掌握程序结构<b class='flag-5'>知识</b>

    C++语言基础知识

    电子发烧友网站提供《C++语言基础知识.pdf》资料免费下载
    发表于 07-19 10:58 7次下载

    科普EEPROM 科普 EVASH Ultra EEPROM 科普存储芯片

    科普EEPROM 科普 EVASH Ultra EEPROM 科普存储芯片
    的头像 发表于 06-25 17:14 568次阅读

    PLC编程语言C语言的区别

    在工业自动化和计算机编程领域中,PLC(可编程逻辑控制器)编程语言C语言各自扮演着重要的角色。尽管两者都是编程语言,但它们在多个方面存在显著的区别。本文将从多个维度深入探讨PLC编程
    的头像 发表于 06-14 17:11 2811次阅读

    有奖征文!第二届电力电子科普作品创作大赛(中国电源学会和英飞凌联合主办)

    ,这位幕后英雄——电力电子技术,往往并不为大众所熟知。 你,作为电力电子行业的辛勤耕耘者,是否曾想过,将你的知识以通俗的语言分享给更多的人?中国电源学会举办的电力电子科普作品创作大赛,为你搭建了一个展
    发表于 04-11 11:38

    如何成为一名嵌入式C语言高手?

    相关教材、参加在线课程或者参考编程书籍来系统地学习C语言的基础知识,并通过编写简单的程序进行实践。 二、深入了解嵌入式系统的硬件架构和工作原理嵌入式系统通常包含微控制器或微处理器等硬件设备,了解这些设备
    发表于 04-07 16:03

    如何成为一名嵌入式C语言高手?

    相关教材、参加在线课程或者参考编程书籍来系统地学习C语言的基础知识,并通过编写简单的程序进行实践。 二、深入了解嵌入式系统的硬件架构和工作原理嵌入式系统通常包含微控制器或微处理器等硬件设备,了解这些设备
    发表于 03-25 14:12

    C语言基础-为什么要使用C

    当今最流行的 Linux 操作系统和 RDBMS(Relational Database Management System:关系数据库管理系统) MySQL 都是使用 C 语言编写的。
    发表于 03-25 11:20 439次阅读

    C语言中的typedef的应用

    C 语言提供 typedef 关键字,您可以使用它来为类型取一个新的名字。下面的实例为单字节数字定义一个术语 BYTE。
    发表于 03-06 11:34 386次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>中的typedef的应用

    嵌入式C语言面试大挑战

    C++中static关键字除了具有C中的作用还有在类中的使用在类中,static可以用来修饰静态数据成员和静态成员方法静态数据成员
    发表于 03-05 14:18 354次阅读
    嵌入式<b class='flag-5'>C</b><b class='flag-5'>语言</b>面试大挑战

    环保科普馆案例分享:讯维大屏显示系统助力环保理念的深入人心

    展示环保理念、普及环保知识的重要工具。 在环保科普馆中,讯维大屏以其高清晰度、大画面和生动的展示效果,吸引众多参观者的目光。大屏上播放着关于环境污染、生态保护、可持续发展等主题的视频和图片,通过直观的画面和
    的头像 发表于 02-28 14:44 540次阅读
    环保<b class='flag-5'>科普</b>馆案例分享:讯维大屏显示系统助力环保理念的深入人心

    plc编程语言c语言的联系 c语言和PLC有什么区别

    PLC编程语言C语言的联系 PLC(可编程逻辑控制器)是一种针对自动化控制系统的特殊计算机。PLC编程语言是为了控制和管理自动化生产过程中的各种设备而设计的。与之相比,
    的头像 发表于 02-05 14:21 4110次阅读

    c语言,c++,java,python区别

    C语言C++、Java和Python是四种常见的编程语言,各有优点和特点。 C语言
    的头像 发表于 02-05 14:11 2384次阅读

    vb语言c++语言的区别

    VB语言C++语言是两种不同的编程语言,虽然它们都属于高级编程语言,但在设计和用途上有很多区别。下面将详细比较VB
    的头像 发表于 02-01 10:20 2291次阅读