在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

C語言的static究竟限制了誰?介紹一種繞開static限制的方法

冬至子 ? 來源:recan ? 作者:recan ? 2023-07-28 15:10 ? 次閱讀

1 問題來源

就在上個星期,在群里收到一個有關static的討論,我個人覺得挺有意思的,于是打算將其整理成文,希望能夠幫助大家更好地理解和應用static這個關鍵字。

群里的原問題如下:

大佬們,問一個比較低智問題,static修飾的變量不是只能被當前文件所調用嗎?為什么這里在其他.c文件可以調用get_board_led_opr這個函數獲取board_demo_led_opr這個變量的值。

1.jpg

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關鍵字有兩種主要的用法:靜態變量和靜態函數。

靜態變量:

靜態變量是在程序運行期間一直存在的變量,其生命周期從聲明處到程序結束。靜態變量被存儲在靜態數據區,不會受到函數的調用和返回的影響,每次進入函數都會保留上一次的值。靜態變量可以在函數內部或者全局作用域中聲明。在函數內部聲明的靜態變量只能在該函數內部訪問,而在全局作用域中聲明的靜態變量可以在整個文件中訪問。 靜態變量的主要作用: - 維護變量的持久狀態,保持值的連續性。 - 限制變量的作用域,只能在函數內或者文件內訪問。 - 避免與同名的全局變量產生沖突。 示例代碼:

void func()

{

? static int count = 0; // 定義一個靜態變量

? count++;

? printf(“Count: %dn”, count);

}

int main()

{

? func(); // 輸出:Count: 1

? func(); // 輸出:Count: 2

? func(); // 輸出:Count: 3

? return 0;

}

靜態函數:

靜態函數是只能在當前源文件中使用的函數,其作用于只限于聲明所在的文件,無法被其他文件調用。使用static關鍵字修飾函數,可以實現函數的隱藏和封裝。因此,靜態函數的主要作用是限制函數的作用域,防止其他文件訪問該函數,避免命名沖突,并且提高代碼的可讀性和可維護性。 示例代碼:

static void util_func(int value)

{

? printf(“Value: %dn”, 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代碼到底是如何被編譯的

在這里,我不打算一一搬過來,僅僅把一張圖貼過來參考:

1.jpg

我們順著這個思路來拆解跟蹤一下代碼里面的 static。

編寫C代碼(C源代碼里面的static)
main.c
#include
static int g_count = 0;
void func()
{
static int l_count = 0; // 定義一個靜態局部變量
l_count++;
g_count++;
printf("l_count: %d, g_count: %dn", l_count, g_count);
}
static void util_func(int value) //定義一個靜態函數
{
printf("Value: %dn", value);
}
extern void test_func(void);
int main()
{
func();//輸出:l_count:1
func();//輸出:l_count:2
func();//輸出:l_count:3
util_func(10);//可以在當前文件中調用util_func函數,輸出:Value: 10
test_func(); // 調用test.c中的函數
return 0;
}
test.c
// 假設它們都是可以訪問的
extern int l_count;
extern int g_count;
extern void util_func(int value);
void test_func(void)
{
#if 0
l_count++; // 訪問l_count靜態局部變量,編譯報錯
g_count++; // 訪問g_count靜態全局變量,編譯報錯
util_func(100); // 調用main.c中的static函數,編譯報錯
#endif
}
當test_func中的if-0打開后,根據我們上面的理論分析,肯定是編譯不過的,如下:

test_static$ gcc -o test *.c
/usr/bin/ld: /tmp/ccawkyDR.o: in function test_func': test.c:(.text+0xa): undefined reference to l_count'
/usr/bin/ld: test.c:(.text+0x13): undefined reference to l_count' /usr/bin/ld: test.c:(.text+0x19): undefined reference to g_count'
/usr/bin/ld: test.c:(.text+0x22): undefined reference to g_count' /usr/bin/ld: test.c:(.text+0x2c): undefined reference to util_func'
collect2: error: ld returned 1 exit status
像這種就是很明顯的找不到變量或函數的實現體,從而出現找不到引用的 鏈接 錯誤。

去掉這些引用后(if-0)打開,即可編譯成功,且能夠正常運行。

test_static$ gcc -o test *.c
test_static$ ./test
l_count: 1, g_count: 1
l_count: 2, g_count: 2
l_count: 3, g_count: 3
Value: 10
分步拆解1:先看預處理后static的情況
使用的命令下:gcc -c -o main.o main.c -save-temps=obj

這時候我們可以看到 main.i main.s main.o 這幾個文件。

先看main.i 的內容:

忽略前面對頭文件內容的搬運

873 "/usr/include/stdio.h" 3 4

2 "main.c" 2

3 "main.c"

static int g_count = 0;
void func()
{
static int l_count = 0;
l_count++;
g_count++;
printf("l_count: %d, g_count: %dn", l_count, g_count);
}
static void util_func(int value)
{
printf("Value: %dn", value);
}
extern void test_func(void);
int main()
{
func();
func();
func();
util_func(10);
test_func();
return 0;

從上基本可以看到,static還是在的,并且整一個預處理后的代碼,基本保留了源代碼的樣子(原因是我們并沒有使用類似宏定義的內容)。

拆解第2步:看看匯編文件有沒有static的影子

這時候我們要查看的是 main.s 文件:

test_static$ cat main.s
.file "main.c"
.text
.local g_count
.comm g_count,4,4
.section .rodata
.LC0:
.string "l_count: %d, g_count: %dn"
.text
.globl func
.type func, @function
func:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl l_count.2316(%rip), %eax
addl $1, %eax
movl %eax, l_count.2316(%rip)
movl g_count(%rip), %eax
addl $1, %eax
movl %eax, g_count(%rip)
movl g_count(%rip), %edx
movl l_count.2316(%rip), %eax
movl %eax, %esi
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size func, .-func
.section .rodata
.LC1:
.string "Value: %dn"
.text
.type util_func, @function
util_func:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf@PLT
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size util_func, .-util_func
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, %eax
call func
movl $0, %eax
call func
movl $0, %eax
call func
movl $10, %edi
call util_func
call test_func@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.local l_count.2316
.comm l_count.2316,4,4
.ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
初一打開,可能有種不太認識的感覺,沒關系,我們先找到我們能認識的東西。

先找到被static修飾過的內容(靜態全局變量、靜態局部變量、靜態函數)。

1)靜態全局變量g_count:

.file   "main.c"
    .text
    .local  g_count
    .comm   g_count,4,4
    .section        .rodata

2)靜態局部變量l_count:

.LFE2:
.size main, .-main
.local l_count.2316
.comm l_count.2316,4,4
3)靜態函數util_func:

.string "Value: %dn"
    .text
    .type   util_func, @function

util_func:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movl -4(%rbp), %eax
movl %eax, %esi
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf@PLT
nop
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc

由于我們只是對main.c進行匯編,所以看不出全貌,但是能夠確認的是,在匯編文件中,static已經消失了,換句話說,接下來就沒static啥事情了,而是轉為其他信息了。我們接著往下拆解。

拆解第3步:obj文件里面確認沒有static的要素嗎?

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

test_static$ readelf -a main.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 1520 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 14
Section header string table index: 13
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
00000000000000ac 0000000000000000 AX 0 0 1
[ 2] .rela.text RELA 0000000000000000 000003e0
0000000000000150 0000000000000018 I 11 1 8
[ 3] .data PROGBITS 0000000000000000 000000ec
0000000000000000 0000000000000000 WA 0 0 1
[ 4] .bss NOBITS 0000000000000000 000000ec
0000000000000008 0000000000000000 WA 0 0 4
[ 5] .rodata PROGBITS 0000000000000000 000000ec
0000000000000025 0000000000000000 A 0 0 1
[ 6] .comment PROGBITS 0000000000000000 00000111
000000000000002c 0000000000000001 MS 0 0 1
[ 7] .note.GNU-stack PROGBITS 0000000000000000 0000013d
0000000000000000 0000000000000000 0 0 1
[ 8] .note.gnu.propert NOTE 0000000000000000 00000140
0000000000000020 0000000000000000 A 0 0 8
[ 9] .eh_frame PROGBITS 0000000000000000 00000160
0000000000000078 0000000000000000 A 0 0 8
[10] .rela.eh_frame RELA 0000000000000000 00000530
0000000000000048 0000000000000018 I 11 9 8
[11] .symtab SYMTAB 0000000000000000 000001d8
00000000000001b0 0000000000000018 12 13 8
[12] .strtab STRTAB 0000000000000000 00000388
0000000000000053 0000000000000000 0 0 1
[13] .shstrtab STRTAB 0000000000000000 00000578
0000000000000074 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There is no dynamic section in this file.
Relocation section '.rela.text' at offset 0x3e0 contains 14 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000000000a 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0
000000000013 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0
000000000019 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4
000000000022 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4
000000000028 000400000002 R_X86_64_PC32 0000000000000000 .bss - 4
00000000002e 000400000002 R_X86_64_PC32 0000000000000000 .bss + 0
000000000037 000600000002 R_X86_64_PC32 0000000000000000 .rodata - 4
000000000041 000f00000004 R_X86_64_PLT32 0000000000000000 printf - 4
00000000005f 000600000002 R_X86_64_PC32 0000000000000000 .rodata + 16
000000000069 000f00000004 R_X86_64_PLT32 0000000000000000 printf - 4
00000000007e 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4
000000000088 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4
000000000092 000d00000004 R_X86_64_PLT32 0000000000000000 func - 4
0000000000a1 001100000004 R_X86_64_PLT32 0000000000000000 test_func - 4
Relocation section '.rela.eh_frame' at offset 0x530 contains 3 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
000000000040 000200000002 R_X86_64_PC32 0000000000000000 .text + 48
000000000060 000200000002 R_X86_64_PC32 0000000000000000 .text + 70
The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.
Symbol table '.symtab' contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS main.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 4 OBJECT LOCAL DEFAULT 4 g_count
6: 0000000000000000 0 SECTION LOCAL DEFAULT 5
7: 0000000000000004 4 OBJECT LOCAL DEFAULT 4 l_count.2316
8: 0000000000000048 40 FUNC LOCAL DEFAULT 1 util_func
9: 0000000000000000 0 SECTION LOCAL DEFAULT 7
10: 0000000000000000 0 SECTION LOCAL DEFAULT 8
11: 0000000000000000 0 SECTION LOCAL DEFAULT 9
12: 0000000000000000 0 SECTION LOCAL DEFAULT 6
13: 0000000000000000 72 FUNC GLOBAL DEFAULT 1 func
14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND GLOBAL_OFFSET_TABLE
15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND printf
16: 0000000000000070 60 FUNC GLOBAL DEFAULT 1 main
17: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND test_func
No version information found in this file.
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: IBT, SHSTK
recan@ubuntu:~/win_share_workspace/test_share/test_static$
從上面可以看到,g_count、l_count、util_func 都被 LOCAL 修飾了,而非 GLOBAL 的:

5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 g_count
 6: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
 7: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    4 l_count.2316
 8: 0000000000000048    40 FUNC    LOCAL  DEFAULT    1 util_func

究竟這兩者修飾有啥區別,會產生什么影響呢?我們接著往下拆解。

拆解第4步:鏈接后的可執行文件反匯編
前面也說到了,由于我們都只看到 main這個C文件相關 預處理、匯編、obj內容,而沒有看到整個可執行文件的全貌。

執行反匯編看看:

test_static$ objdump -l -d -x -s -S test
test: file format elf64-x86-64
test
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000001060
Program Header:
PHDR off 0x0000000000000040 vaddr 0x0000000000000040 paddr 0x0000000000000040 align 23
filesz 0x00000000000002d8 memsz 0x00000000000002d8 flags r--
INTERP off 0x0000000000000318 vaddr 0x0000000000000318 paddr 0x0000000000000318 align 2
0
filesz 0x000000000000001c memsz 0x000000000000001c flags r--
LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 212
filesz 0x0000000000000600 memsz 0x0000000000000600 flags r--
LOAD off 0x0000000000001000 vaddr 0x0000000000001000 paddr 0x0000000000001000 align 2
12
filesz 0x0000000000000285 memsz 0x0000000000000285 flags r-x
LOAD off 0x0000000000002000 vaddr 0x0000000000002000 paddr 0x0000000000002000 align 212
filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags r--
LOAD off 0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 2
12
filesz 0x0000000000000258 memsz 0x0000000000000268 flags rw-
DYNAMIC off 0x0000000000002dc8 vaddr 0x0000000000003dc8 paddr 0x0000000000003dc8 align 23
filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags rw-
NOTE off 0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2
3
filesz 0x0000000000000020 memsz 0x0000000000000020 flags r--
NOTE off 0x0000000000000358 vaddr 0x0000000000000358 paddr 0x0000000000000358 align 22
filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
0x6474e553 off 0x0000000000000338 vaddr 0x0000000000000338 paddr 0x0000000000000338 align 2
3
filesz 0x0000000000000020 memsz 0x0000000000000020 flags r--
EH_FRAME off 0x000000000000202c vaddr 0x000000000000202c paddr 0x000000000000202c align 22
filesz 0x000000000000005c memsz 0x000000000000005c flags r--
STACK off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2
4
filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
RELRO off 0x0000000000002db8 vaddr 0x0000000000003db8 paddr 0x0000000000003db8 align 20
filesz 0x0000000000000248 memsz 0x0000000000000248 flags r--
Dynamic Section:
NEEDED libc.so.6
INIT 0x0000000000001000
FINI 0x0000000000001278
INIT_ARRAY 0x0000000000003db8
INIT_ARRAYSZ 0x0000000000000008
FINI_ARRAY 0x0000000000003dc0
FINI_ARRAYSZ 0x0000000000000008
GNU_HASH 0x00000000000003a0
STRTAB 0x0000000000000470
SYMTAB 0x00000000000003c8
STRSZ 0x0000000000000084
SYMENT 0x0000000000000018
DEBUG 0x0000000000000000
PLTGOT 0x0000000000003fb8
PLTRELSZ 0x0000000000000018
PLTREL 0x0000000000000007
JMPREL 0x00000000000005e8
RELA 0x0000000000000528
RELASZ 0x00000000000000c0
RELAENT 0x0000000000000018
FLAGS 0x0000000000000008
FLAGS_1 0x0000000008000001
VERNEED 0x0000000000000508
VERNEEDNUM 0x0000000000000001
VERSYM 0x00000000000004f4
RELACOUNT 0x0000000000000003
Version References:
required from libc.so.6:
0x09691a75 0x00 02 GLIBC_2.2.5
Sections:
Idx Name Size VMA LMA File off Algn
0 .interp 0000001c 0000000000000318 0000000000000318 00000318 2
0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .note.gnu.property 00000020 0000000000000338 0000000000000338 00000338 23
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .note.gnu.build-id 00000024 0000000000000358 0000000000000358 00000358 2
2
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .note.ABI-tag 00000020 000000000000037c 000000000000037c 0000037c 22
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .gnu.hash 00000024 00000000000003a0 00000000000003a0 000003a0 2
3
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .dynsym 000000a8 00000000000003c8 00000000000003c8 000003c8 23
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .dynstr 00000084 0000000000000470 0000000000000470 00000470 2
0
CONTENTS, ALLOC, LOAD, READONLY, DATA
7 .gnu.version 0000000e 00000000000004f4 00000000000004f4 000004f4 21
CONTENTS, ALLOC, LOAD, READONLY, DATA
8 .gnu.version_r 00000020 0000000000000508 0000000000000508 00000508 2
3
CONTENTS, ALLOC, LOAD, READONLY, DATA
9 .rela.dyn 000000c0 0000000000000528 0000000000000528 00000528 23
CONTENTS, ALLOC, LOAD, READONLY, DATA
10 .rela.plt 00000018 00000000000005e8 00000000000005e8 000005e8 2
3
CONTENTS, ALLOC, LOAD, READONLY, DATA
11 .init 0000001b 0000000000001000 0000000000001000 00001000 22
CONTENTS, ALLOC, LOAD, READONLY, CODE
12 .plt 00000020 0000000000001020 0000000000001020 00001020 2
4
CONTENTS, ALLOC, LOAD, READONLY, CODE
13 .plt.got 00000010 0000000000001040 0000000000001040 00001040 24
CONTENTS, ALLOC, LOAD, READONLY, CODE
14 .plt.sec 00000010 0000000000001050 0000000000001050 00001050 2
4
CONTENTS, ALLOC, LOAD, READONLY, CODE
15 .text 00000215 0000000000001060 0000000000001060 00001060 24
CONTENTS, ALLOC, LOAD, READONLY, CODE
16 .fini 0000000d 0000000000001278 0000000000001278 00001278 2
2
CONTENTS, ALLOC, LOAD, READONLY, CODE
17 .rodata 00000029 0000000000002000 0000000000002000 00002000 22
CONTENTS, ALLOC, LOAD, READONLY, DATA
18 .eh_frame_hdr 0000005c 000000000000202c 000000000000202c 0000202c 2
2
CONTENTS, ALLOC, LOAD, READONLY, DATA
19 .eh_frame 00000168 0000000000002088 0000000000002088 00002088 23
CONTENTS, ALLOC, LOAD, READONLY, DATA
20 .init_array 00000008 0000000000003db8 0000000000003db8 00002db8 2
3
CONTENTS, ALLOC, LOAD, DATA
21 .fini_array 00000008 0000000000003dc0 0000000000003dc0 00002dc0 23
CONTENTS, ALLOC, LOAD, DATA
22 .dynamic 000001f0 0000000000003dc8 0000000000003dc8 00002dc8 2
3
CONTENTS, ALLOC, LOAD, DATA
23 .got 00000048 0000000000003fb8 0000000000003fb8 00002fb8 23
CONTENTS, ALLOC, LOAD, DATA
24 .data 00000010 0000000000004000 0000000000004000 00003000 2
3
CONTENTS, ALLOC, LOAD, DATA
25 .bss 00000010 0000000000004010 0000000000004010 00003010 22
ALLOC
26 .comment 0000002b 0000000000000000 0000000000000000 00003010 2
0
CONTENTS, READONLY
SYMBOL TABLE:
0000000000000318 l d .interp 0000000000000000 .interp
0000000000000338 l d .note.gnu.property 0000000000000000 .note.gnu.property
0000000000000358 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id
000000000000037c l d .note.ABI-tag 0000000000000000 .note.ABI-tag
00000000000003a0 l d .gnu.hash 0000000000000000 .gnu.hash
00000000000003c8 l d .dynsym 0000000000000000 .dynsym
0000000000000470 l d .dynstr 0000000000000000 .dynstr
00000000000004f4 l d .gnu.version 0000000000000000 .gnu.version
0000000000000508 l d .gnu.version_r 0000000000000000 .gnu.version_r
0000000000000528 l d .rela.dyn 0000000000000000 .rela.dyn
00000000000005e8 l d .rela.plt 0000000000000000 .rela.plt
0000000000001000 l d .init 0000000000000000 .init
0000000000001020 l d .plt 0000000000000000 .plt
0000000000001040 l d .plt.got 0000000000000000 .plt.got
0000000000001050 l d .plt.sec 0000000000000000 .plt.sec
0000000000001060 l d .text 0000000000000000 .text
0000000000001278 l d .fini 0000000000000000 .fini
0000000000002000 l d .rodata 0000000000000000 .rodata
000000000000202c l d .eh_frame_hdr 0000000000000000 .eh_frame_hdr
0000000000002088 l d .eh_frame 0000000000000000 .eh_frame
0000000000003db8 l d .init_array 0000000000000000 .init_array
0000000000003dc0 l d .fini_array 0000000000000000 .fini_array
0000000000003dc8 l d .dynamic 0000000000000000 .dynamic
0000000000003fb8 l d .got 0000000000000000 .got
0000000000004000 l d .data 0000000000000000 .data
0000000000004010 l d .bss 0000000000000000 .bss
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000000 l df ABS 0000000000000000 crtstuff.c
0000000000001090 l F .text 0000000000000000 deregister_tm_clones
00000000000010c0 l F .text 0000000000000000 register_tm_clones
0000000000001100 l F .text 0000000000000000 __do_global_dtors_aux
0000000000004010 l O .bss 0000000000000001 completed.8061
0000000000003dc0 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry
0000000000001140 l F .text 0000000000000000 frame_dummy
0000000000003db8 l O .init_array 0000000000000000 __frame_dummy_init_array_entry
0000000000000000 l df ABS 0000000000000000 main.c
0000000000004014 l O .bss 0000000000000004 g_count
0000000000004018 l O .bss 0000000000000004 l_count.2316
0000000000001191 l F .text 0000000000000028 util_func
0000000000000000 l df ABS 0000000000000000 test.c
0000000000000000 l df ABS 0000000000000000 crtstuff.c
00000000000021ec l O .eh_frame 0000000000000000 FRAME_END
0000000000000000 l df ABS 0000000000000000
0000000000003dc0 l .init_array 0000000000000000 __init_array_end
0000000000003dc8 l O .dynamic 0000000000000000 _DYNAMIC
0000000000003db8 l .init_array 0000000000000000 __init_array_start
000000000000202c l .eh_frame_hdr 0000000000000000 __GNU_EH_FRAME_HDR
0000000000003fb8 l O .got 0000000000000000 GLOBAL_OFFSET_TABLE
0000000000001000 l F .init 0000000000000000 _init
0000000000001270 g F .text 0000000000000005 __libc_csu_fini
0000000000000000 w UND 0000000000000000 _ITM_deregisterTMCloneTable
0000000000004000 w .data 0000000000000000 data_start
0000000000004010 g .data 0000000000000000 _edata
0000000000001278 g F .fini 0000000000000000 .hidden _fini
0000000000000000 F UND 0000000000000000 printf@@GLIBC_2.2.5
00000000000011f5 g F .text 000000000000000b test_func
0000000000000000 F UND 0000000000000000 __libc_start_main@@GLIBC_2.2.5
0000000000004000 g .data 0000000000000000 __data_start
0000000000000000 w UND 0000000000000000 gmon_start
0000000000004008 g O .data 0000000000000000 .hidden __dso_handle
0000000000002000 g O .rodata 0000000000000004 _IO_stdin_used
0000000000001149 g F .text 0000000000000048 func
0000000000001200 g F .text 0000000000000065 __libc_csu_init
0000000000004020 g .bss 0000000000000000 _end
0000000000001060 g F .text 000000000000002f _start
0000000000004010 g .bss 0000000000000000 __bss_start
00000000000011b9 g F .text 000000000000003c main
0000000000004010 g O .data 0000000000000000 .hidden TMC_END
0000000000000000 w UND 0000000000000000 _ITM_registerTMCloneTable
0000000000000000 w F UND 0000000000000000 __cxa_finalize@@GLIBC_2.2.5
Contents of section .interp:
0318 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
0328 7838362d 36342e73 6f2e3200 x86-64.so.2.
省略了一些無關緊要的內容
Contents of section .data:
4000 00000000 00000000 08400000 00000000 .........@......
Contents of section .comment:
0000 4743433a 20285562 756e7475 20392e34 GCC: (Ubuntu 9.4
0010 2e302d31 7562756e 7475317e 32302e30 .0-1ubuntu1~20.0
0020 342e3129 20392e34 2e3000 4.1) 9.4.0.
Disassembly of section .init:
0000000000001000 <_init>:
_init():
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 < gmon_start >
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 callq *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 retq
Disassembly of section .plt:
0000000000001020 <.plt>:
1020: ff 35 9a 2f 00 00 pushq 0x2f9a(%rip) # 3fc0 < GLOBAL_OFFSET_TABLE +0x8>
1026: f2 ff 25 9b 2f 00 00 bnd jmpq *0x2f9b(%rip) # 3fc8 < GLOBAL_OFFSET_TABLE +0x10>
102d: 0f 1f 00 nopl (%rax)
1030: f3 0f 1e fa endbr64
1034: 68 00 00 00 00 pushq $0x0
1039: f2 e9 e1 ff ff ff bnd jmpq 1020 <.plt>
103f: 90 nop
Disassembly of section .plt.got:
0000000000001040 <__cxa_finalize@plt>:
1040: f3 0f 1e fa endbr64
1044: f2 ff 25 ad 2f 00 00 bnd jmpq *0x2fad(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
104b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .plt.sec:
0000000000001050 :
1050: f3 0f 1e fa endbr64
1054: f2 ff 25 75 2f 00 00 bnd jmpq *0x2f75(%rip) # 3fd0
105b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .text:
0000000000001060 <_start>:
_start():
1060: f3 0f 1e fa endbr64
1064: 31 ed xor %ebp,%ebp
1066: 49 89 d1 mov %rdx,%r9
1069: 5e pop %rsi
106a: 48 89 e2 mov %rsp,%rdx
106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1071: 50 push %rax
1072: 54 push %rsp
1073: 4c 8d 05 f6 01 00 00 lea 0x1f6(%rip),%r8 # 1270 <__libc_csu_fini>
107a: 48 8d 0d 7f 01 00 00 lea 0x17f(%rip),%rcx # 1200 <__libc_csu_init>
1081: 48 8d 3d 31 01 00 00 lea 0x131(%rip),%rdi # 11b9

1088: ff 15 52 2f 00 00 callq *0x2f52(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5>
108e: f4 hlt
108f: 90 nop
0000000000001090 :
deregister_tm_clones():
1090: 48 8d 3d 79 2f 00 00 lea 0x2f79(%rip),%rdi # 4010 < TMC_END >
1097: 48 8d 05 72 2f 00 00 lea 0x2f72(%rip),%rax # 4010 < TMC_END >
109e: 48 39 f8 cmp %rdi,%rax
10a1: 74 15 je 10b8
10a3: 48 8b 05 2e 2f 00 00 mov 0x2f2e(%rip),%rax # 3fd8 <_ITM_deregisterTMCloneTable>
10aa: 48 85 c0 test %rax,%rax
10ad: 74 09 je 10b8
10af: ff e0 jmpq *%rax
10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10b8: c3 retq
10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000010c0 :
register_tm_clones():
10c0: 48 8d 3d 49 2f 00 00 lea 0x2f49(%rip),%rdi # 4010 < TMC_END >
10c7: 48 8d 35 42 2f 00 00 lea 0x2f42(%rip),%rsi # 4010 < TMC_END >
10ce: 48 29 fe sub %rdi,%rsi
10d1: 48 89 f0 mov %rsi,%rax
10d4: 48 c1 ee 3f shr $0x3f,%rsi
10d8: 48 c1 f8 03 sar $0x3,%rax
10dc: 48 01 c6 add %rax,%rsi
10df: 48 d1 fe sar %rsi
10e2: 74 14 je 10f8
10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable>
10eb: 48 85 c0 test %rax,%rax
10ee: 74 08 je 10f8
10f0: ff e0 jmpq *%rax
10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
10f8: c3 retq
10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001100 <__do_global_dtors_aux>:
__do_global_dtors_aux():
1100: f3 0f 1e fa endbr64
1104: 80 3d 05 2f 00 00 00 cmpb $0x0,0x2f05(%rip) # 4010 < TMC_END >
110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38>
110d: 55 push %rbp
110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1115: 00
1116: 48 89 e5 mov %rsp,%rbp
1119: 74 0c je 1127 <__do_global_dtors_aux+0x27>
111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle>
1122: e8 19 ff ff ff callq 1040 <__cxa_finalize@plt>
1127: e8 64 ff ff ff callq 1090
112c: c6 05 dd 2e 00 00 01 movb $0x1,0x2edd(%rip) # 4010 < TMC_END >
1133: 5d pop %rbp
1134: c3 retq
1135: 0f 1f 00 nopl (%rax)
1138: c3 retq
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001140 :
frame_dummy():
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmpq 10c0
0000000000001149 :
func():
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 8b 05 c1 2e 00 00 mov 0x2ec1(%rip),%eax # 4018
1157: 83 c0 01 add $0x1,%eax
115a: 89 05 b8 2e 00 00 mov %eax,0x2eb8(%rip) # 4018
1160: 8b 05 ae 2e 00 00 mov 0x2eae(%rip),%eax # 4014
1166: 83 c0 01 add $0x1,%eax
1169: 89 05 a5 2e 00 00 mov %eax,0x2ea5(%rip) # 4014
116f: 8b 15 9f 2e 00 00 mov 0x2e9f(%rip),%edx # 4014
1175: 8b 05 9d 2e 00 00 mov 0x2e9d(%rip),%eax # 4018
117b: 89 c6 mov %eax,%esi
117d: 48 8d 3d 80 0e 00 00 lea 0xe80(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
1184: b8 00 00 00 00 mov $0x0,%eax
1189: e8 c2 fe ff ff callq 1050
118e: 90 nop
118f: 5d pop %rbp
1190: c3 retq
0000000000001191 :
util_func():
1191: f3 0f 1e fa endbr64
1195: 55 push %rbp
1196: 48 89 e5 mov %rsp,%rbp
1199: 48 83 ec 10 sub $0x10,%rsp
119d: 89 7d fc mov %edi,-0x4(%rbp)
11a0: 8b 45 fc mov -0x4(%rbp),%eax
11a3: 89 c6 mov %eax,%esi
11a5: 48 8d 3d 72 0e 00 00 lea 0xe72(%rip),%rdi # 201e <_IO_stdin_used+0x1e>
11ac: b8 00 00 00 00 mov $0x0,%eax
11b1: e8 9a fe ff ff callq 1050
11b6: 90 nop
11b7: c9 leaveq
11b8: c3 retq
00000000000011b9 :
main():
11b9: f3 0f 1e fa endbr64
11bd: 55 push %rbp
11be: 48 89 e5 mov %rsp,%rbp
11c1: b8 00 00 00 00 mov $0x0,%eax
11c6: e8 7e ff ff ff callq 1149
11cb: b8 00 00 00 00 mov $0x0,%eax
11d0: e8 74 ff ff ff callq 1149
11d5: b8 00 00 00 00 mov $0x0,%eax
11da: e8 6a ff ff ff callq 1149
11df: bf 0a 00 00 00 mov $0xa,%edi
11e4: e8 a8 ff ff ff callq 1191
11e9: e8 07 00 00 00 callq 11f5
11ee: b8 00 00 00 00 mov $0x0,%eax
11f3: 5d pop %rbp
11f4: c3 retq
00000000000011f5 :
test_func():
11f5: f3 0f 1e fa endbr64
11f9: 55 push %rbp
11fa: 48 89 e5 mov %rsp,%rbp
11fd: 90 nop
11fe: 5d pop %rbp
11ff: c3 retq
0000000000001200 <__libc_csu_init>:
__libc_csu_init():
1200: f3 0f 1e fa endbr64
1204: 41 57 push %r15
1206: 4c 8d 3d ab 2b 00 00 lea 0x2bab(%rip),%r15 # 3db8 <__frame_dummy_init_array_entry>
120d: 41 56 push %r14
120f: 49 89 d6 mov %rdx,%r14
1212: 41 55 push %r13
1214: 49 89 f5 mov %rsi,%r13
1217: 41 54 push %r12
1219: 41 89 fc mov %edi,%r12d
121c: 55 push %rbp
121d: 48 8d 2d 9c 2b 00 00 lea 0x2b9c(%rip),%rbp # 3dc0 <__do_global_dtors_aux_fini_array_entry>
1224: 53 push %rbx
1225: 4c 29 fd sub %r15,%rbp
1228: 48 83 ec 08 sub $0x8,%rsp
122c: e8 cf fd ff ff callq 1000 <_init>
1231: 48 c1 fd 03 sar $0x3,%rbp
1235: 74 1f je 1256 <__libc_csu_init+0x56>
1237: 31 db xor %ebx,%ebx
1239: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
1240: 4c 89 f2 mov %r14,%rdx
1243: 4c 89 ee mov %r13,%rsi
1246: 44 89 e7 mov %r12d,%edi
1249: 41 ff 14 df callq *(%r15,%rbx,8)
124d: 48 83 c3 01 add $0x1,%rbx
1251: 48 39 dd cmp %rbx,%rbp
1254: 75 ea jne 1240 <__libc_csu_init+0x40>
1256: 48 83 c4 08 add $0x8,%rsp
125a: 5b pop %rbx
125b: 5d pop %rbp
125c: 41 5c pop %r12
125e: 41 5d pop %r13
1260: 41 5e pop %r14
1262: 41 5f pop %r15
1264: c3 retq
1265: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1)
126c: 00 00 00 00
0000000000001270 <__libc_csu_fini>:
__libc_csu_fini():
1270: f3 0f 1e fa endbr64
1274: c3 retq
Disassembly of section .fini:
0000000000001278 <_fini>:
_fini():
1278: f3 0f 1e fa endbr64
127c: 48 83 ec 08 sub $0x8,%rsp
1280: 48 83 c4 08 add $0x8,%rsp
1284: c3 retq

老規矩,看不懂全部不重要,找你能看得懂的。

還是找到 l_count 、g_count、util_test 這幾個來吧。

1.jpg

看樣子也沒啥特殊的,所以問題的關鍵還在前一步:鏈接器那里。

綜上可知,static的修飾主要是給編譯器做了提示,從而生成的obj文件中帶了 local屬性,這樣就告訴鏈接器,不能擴大這些被local修飾過的內容的使用范圍,從而達到了教科書上面說的那樣static的作用效果。

其實還有一個方法,就是你寫一個帶static和不帶static的,比如都是全局變量的兩個,通過反匯編來對比分析,這樣也可以快速看出核心區別,就留給讀者去探索吧。

再留一個疑問:編譯器、鏈接器 如何做到一個static修飾的局部變量,只能被定義的當前函數內訪問的?

這個問題,有點深入,也留給讀者去探索吧。

5 一種繞開static限制的方法
談到繞開static的限制,其實本文第1小節的那個問題例子就是一個很好的思路和方法。

要想繞開static的限制,無非就是:

將被static修飾的函數轉換為沒有被static修飾的函數 !

或者

將被static修飾的變量轉換為沒有被static修飾的變量 !

這個做法,還有一個行業名詞叫:封裝 。

在第1小節中,代碼中演示的是將被static修飾的變量,通過傳出其地址,以指針的形式導出給外部模塊使用。

下面的代碼片段,將展示將被static修飾的函數,轉換為沒有被static修飾的函數,從而給外部模塊使用。

test_a.c

static int test_func_in_a(int a)

int test_func_in_a_ex(int a)

test_b.c
int test_func_in_b(void)
{
int a = 1;
int b;
//call test_func_in_a function fail because of "static"
//b = test_func_in_a(a)
//call test_func_in_a_ex function ok without "static"
b = test_func_in_a_ex(a)
return b;
}

示例代碼很簡單,僅僅就是在_test_a.c 中,編寫一個不被static修飾的函數 test_func_in_a_ex,然后它去調用被static修飾的test_func_in_a函數,這樣就輕松繞開了static的限制。

你學會了嗎?

6 拓展延伸:如何調用靜態庫里的被static修飾的函數?

關于這個擴展延伸,其實我很早就起草了一篇博文想寫這個內容來著,但是一直拖,一直拖,直到現在還沒生產。

索性就在本文做個牽引吧!

個人認為,對于此問題,應該分為兩個場景:

靜態庫的代碼,你有修改的權限;或者你能找到人來修改;比如,公司內部不同團隊直接的公有庫代碼;

靜態庫的代碼,你完全沒辦法查看源碼或修改源碼;比如一些第三方的庫。

針對這兩種不同的場景,可能采取的方式是不一樣的,你覺得應該如何做最好呢?

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C語言
    +關注

    關注

    180

    文章

    7604

    瀏覽量

    136827
  • static
    +關注

    關注

    0

    文章

    33

    瀏覽量

    10371
  • ChatGPT
    +關注

    關注

    29

    文章

    1561

    瀏覽量

    7671
收藏 人收藏

    評論

    相關推薦

    C語言static的作用(轉載)

    就是在各自文件中,在相同的全局變量申明前加上static修飾符。這樣系統就會為他們分配不同的內存,互不影響了。在C語言static的作用如下:第
    發表于 01-23 16:49

    究竟是什么限制電池的容量?

    究竟是什么限制電池的容量?”句話的簡單回答是:電池背后的化學限制電池的能量密度。
    發表于 05-05 09:50 ?6677次閱讀

    C語言static作用

      在C語言中,static的字面意思很容易把我們導入歧途,其實它的作用有三條。當我們同時編譯多個文件時,所有未加static前綴的全局變量和函數都具有全局可見性。
    發表于 09-18 10:26 ?8次下載

    java中static的作用及常見的誤區

    .static關鍵字的用途 二.static關鍵字的誤區 三。常見的筆試面試題 .static關鍵字的用途 在《Java編程思想》P86
    發表于 09-27 10:44 ?0次下載
    java中<b class='flag-5'>static</b>的作用及常見的誤區

    java中static關鍵字的作用

    列舉了些面試筆試中常見的關于static的考題。 以下是本文的目錄大綱: .static關鍵字的用途 二.static關鍵字的誤區 三。
    發表于 09-27 17:12 ?0次下載

    c語言static的作用

    C語言static的作用如下第、在修飾變量的時候,static修飾的靜態局部變量只執行
    發表于 11-03 09:36 ?1.5w次閱讀

    C語言static和extern的區別介紹

    、在C中,static主要定義全局靜態變量、定義局部靜態變量、定義靜態函數。 1、定義全局靜態變量:在全局變量前面加上關鍵字static,該全局變量變成了全局靜態變量。全局靜態變量有
    發表于 11-21 10:23 ?6次下載

    C語言關鍵字static有哪些絕妙用途

    為什么要說static妙,它確實是妙,在軟件開發或者單片機開發過程中,大家總以為static就是個靜態變量,在變量類型的前面加上就自動清0,還有就是加上
    發表于 07-18 17:38 ?1次下載
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>關鍵字<b class='flag-5'>static</b>有哪些絕妙用途

    單片機static關鍵字的主要作用

    1、限制變量或函數的作用域被static修飾的全局變量或者函數,只能在本c文件訪問,其他c文件不能訪問2、設置變量的存儲域局部變量是放在棧當中,被s
    發表于 11-21 09:21 ?11次下載
    單片機<b class='flag-5'>static</b>關鍵字的主要作用

    JAVA中static、final、static final如何區分

    當我們在使用java寫類的屬性時總會用到很多的類型去修飾它,比如字符串String,整數型int,但是我們偶爾也會遇到 static、final、static final,那么他們的區別是什么呢?
    的頭像 發表于 02-14 14:55 ?1194次閱讀
    JAVA中<b class='flag-5'>static</b>、final、<b class='flag-5'>static</b> final如何區分

    【筆記】staticC語言中的用法

    當`static`關鍵字用于不同的上下文時,其含義和作用也會有所不同。下面是更多示例代碼,展示`static`在不同用法下的具體效果:示例1:靜態局部變量#includevoidincrement
    的頭像 發表于 06-12 10:03 ?997次閱讀
    【筆記】<b class='flag-5'>static</b> 在<b class='flag-5'>C</b><b class='flag-5'>語言</b>中的用法

    【知識科普】C語言static究竟限制

    【知識科普】C語言static究竟限制? 這是
    的頭像 發表于 08-02 20:05 ?905次閱讀
    【知識科普】<b class='flag-5'>C</b><b class='flag-5'>語言</b>的<b class='flag-5'>static</b><b class='flag-5'>究竟</b><b class='flag-5'>限制</b><b class='flag-5'>了</b><b class='flag-5'>誰</b>

    static定義內部類

    個獨立的程序類。需要注意,static定義的不管是類還是方法只能夠訪問static成員, 所以st
    的頭像 發表于 10-10 16:08 ?557次閱讀

    Java中對static關鍵詞的介紹

    static 是Java的個關鍵字,可以用來修飾成員變量、修飾成員方法、構造靜態代碼塊、實現靜態導包以及實現靜態內部類,下面我們來分別介紹。 1、修飾成員變量 用
    的頭像 發表于 10-11 15:26 ?486次閱讀
    Java中對<b class='flag-5'>static</b>關鍵詞的<b class='flag-5'>介紹</b>

    static關鍵字的三用法

    變量(StaticVariables):在C語言中,使用`static`關鍵字來聲明靜態變量是一種常見的用法,它具有以下主要作用:1.生存期延長:靜態變量的生存期在程序的整個運行期間,
    的頭像 發表于 11-10 08:00 ?521次閱讀
    <b class='flag-5'>static</b>關鍵字的三<b class='flag-5'>種</b>用法
    主站蜘蛛池模板: 男女视频在线看| 免费看黄资源大全高清| www.av在线| 久久久午夜视频| 久久国产热| 亚洲aⅴ久久久噜噜噜噜| 四虎影院精品在线观看| 日本久本草精品| 新版天堂资源在线官网8| 欧美极品在线| 色婷婷六月| 狠狠色丁香婷婷综合视频| 免费一级特黄特色大片| 国产成人精品亚洲日本在线观看| 欧美freesex| 永久视频免费| 3344在线观看永久免费| 日韩在线网| 午夜逼逼| 久久国产精品自在自线| 久久福利青草精品资源| 正在播放国产女免费| 国产黄视频网站| 亚欧成人乱码一区二区| 成人久久网站| 国产片一级| 婷婷丁香五| 国产精品三级在线观看| 免费人成黄页在线观看1024| 欲色影视香色天天影视来| 国产性videosgratis| 日本xxxxxx69| 日本黄色小视频| 久久精品免费看| 婷婷激情六月| 天天干天天操天天玩| 在线资源天堂| 悠悠影院欧美日韩国产| 亚洲成人免费网站| 国产一线在线观看| 国产综合在线视频|