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

    文章

    1266

    浏览量

    39858

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

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

收藏 人收藏

    评论

    相关推荐

    C语言与Java语言的对比

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

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

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

    PLC编程语言C语言的区别

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

    嵌入式C语言面试大挑战

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

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

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

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

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

    vb语言c++语言的区别

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

    C语言代码的常用技巧

    #和##对于大部分C语言玩得还算比较溜的朋友并不是很陌生,不过能把这两个知识点游刃有余的应用到所在代码中的每个角落,似乎并没有几个人能够做到,学的时候朗朗上口,而编码的时候却抛之脑后。
    的头像 发表于 12-05 09:25 516次阅读
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>代码的常用技巧

    C语言必备知识头文件包含

    头文件在C语言中是非常重要的组成部分。
    的头像 发表于 12-01 18:20 1801次阅读

    C语言运行环境是什么

    C语言运行环境(C language runtime environment)是指在执行C语言程序时所需的软件及硬件环境。
    的头像 发表于 11-27 16:13 3296次阅读

    如何选择创建c语言c++

    选择创建 C 语言C++ 都需要综合考虑多个因素。在决定使用哪种语言之前,我们需要对这两种语言的特点、优缺点、适用场景、学习成本等进行全
    的头像 发表于 11-27 15:58 560次阅读

    c语言程序设计基础知识

    程序设计的基础知识点。 首先,我们将从C语言的数据类型和变量开始。C语言提供多种数据类型,包括
    的头像 发表于 11-27 15:25 1577次阅读

    C语言编程必备知识合集

    电子发烧友网站提供《C语言编程必备知识合集.zip》资料免费下载
    发表于 11-21 09:34 0次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b>编程必备<b class='flag-5'>知识</b>合集