ตัวอย่างขอบเขตหลายไฟล์ที่รันได้น้อยที่สุด
ที่นี่ฉันแสดงให้เห็นว่าstatic
มีผลกระทบต่อขอบเขตของคำนิยามฟังก์ชั่นในหลายไฟล์
ไฟฟ้ากระแสสลับ
#include <stdio.h>
/* Undefined behavior: already defined in main.
* Binutils 2.24 gives an error and refuses to link.
* /programming/27667277/why-does-borland-compile-with-multiple-definitions-of-same-object-in-different-c
*/
/*void f() { puts("a f"); }*/
/* OK: only declared, not defined. Will use the one in main. */
void f(void);
/* OK: only visible to this file. */
static void sf() { puts("a sf"); }
void a() {
f();
sf();
}
main.c
#include <stdio.h>
void a(void);
void f() { puts("main f"); }
static void sf() { puts("main sf"); }
void m() {
f();
sf();
}
int main() {
m();
a();
return 0;
}
GitHub ต้นน้ำ
รวบรวมและเรียกใช้:
gcc -c a.c -o a.o
gcc -c main.c -o main.o
gcc -o main main.o a.o
./main
เอาท์พุท:
main f
main sf
main f
a sf
การตีความ
- มีฟังก์ชั่นแยกกันสองฟังก์ชั่น
sf
หนึ่งสำหรับแต่ละไฟล์
- มีฟังก์ชั่นที่ใช้ร่วมกันเดียว
f
ตามปกติขอบเขตที่เล็กลงจะดีกว่าดังนั้นจะประกาศฟังก์ชั่นเสมอstatic
ถ้าทำได้
ในการเขียนโปรแกรม C ไฟล์มักจะใช้เพื่อแสดง "คลาส" และstatic
ฟังก์ชั่นแสดงวิธีการ "ส่วนตัว" ของชั้นเรียน
รูปแบบ C ทั่วไปคือการส่งผ่านthis
struct รอบ ๆ เป็นอาร์กิวเมนต์ "วิธี" แรกซึ่งเป็นสิ่ง C + + ทำภายใต้ประทุน
มาตรฐานพูดถึงอะไร
C99 N1256 ฉบับร่าง 6.7.1 "ตัวระบุคลาสหน่วยเก็บข้อมูล" ระบุว่าstatic
เป็น "ตัวระบุระดับชั้นเก็บข้อมูล"
6.2.2 / 3 "การเชื่อมโยงของตัวระบุ" กล่าวstatic
ถึงนัยinternal linkage
:
หากการประกาศของตัวระบุขอบเขตไฟล์สำหรับวัตถุหรือฟังก์ชั่นมีตัวระบุคลาสเก็บข้อมูลแบบคงที่ตัวระบุมีการเชื่อมโยงภายใน
และ 6.2.2 / 2 บอกว่ามันinternal linkage
มีพฤติกรรมเหมือนในตัวอย่างของเรา:
ในชุดของหน่วยการแปลและไลบรารีที่ประกอบด้วยโปรแกรมทั้งหมดการประกาศของตัวระบุเฉพาะที่มีการเชื่อมโยงภายนอกจะแสดงวัตถุหรือฟังก์ชันเดียวกัน ภายในหนึ่งหน่วยการแปลการประกาศของตัวระบุแต่ละตัวที่มีการเชื่อมโยงภายในหมายถึงวัตถุหรือฟังก์ชันเดียวกัน
โดยที่ "หน่วยการแปล" เป็นไฟล์ต้นฉบับหลังจากประมวลผลล่วงหน้า
GCC ใช้สำหรับ ELF (Linux) ได้อย่างไร
ด้วยการSTB_LOCAL
ผูกมัด
ถ้าเรารวบรวม:
int f() { return 0; }
static int sf() { return 0; }
และแยกตารางสัญลักษณ์ด้วย:
readelf -s main.o
ผลลัพธ์ประกอบด้วย:
Num: Value Size Type Bind Vis Ndx Name
5: 000000000000000b 11 FUNC LOCAL DEFAULT 1 sf
9: 0000000000000000 11 FUNC GLOBAL DEFAULT 1 f
ดังนั้นการผูกเป็นความแตกต่างที่สำคัญระหว่างพวกเขา Value
เป็นเพียงส่วนชดเชยของพวกเขาใน.bss
ส่วนดังนั้นเราจึงคาดหวังว่ามันจะแตกต่างกัน
STB_LOCAL
เป็นเอกสารเกี่ยวกับข้อมูลจำเพาะของเอลฟ์ที่http://www.sco.com/developers/gabi/2003-12-17/ch4.symtab.html :
STB_LOCAL สัญลักษณ์ท้องถิ่นจะมองไม่เห็นนอกไฟล์วัตถุที่มีคำจำกัดความของพวกเขา สัญลักษณ์โลคอลที่มีชื่อเดียวกันอาจมีอยู่ในหลายไฟล์โดยไม่รบกวนซึ่งกันและกัน
static
ซึ่งจะทำให้มันเป็นทางเลือกที่สมบูรณ์แบบที่จะเป็นตัวแทน
ฟังก์ชั่นที่ไม่มีสถิตคือSTB_GLOBAL
และ spec บอกว่า:
เมื่อตัวแก้ไขลิงก์รวมหลายอ็อบเจ็กต์ไฟล์ที่เปลี่ยนตำแหน่งได้มันไม่อนุญาตให้นิยามหลาย ๆ สัญลักษณ์ STB_GLOBAL ด้วยชื่อเดียวกัน
ซึ่งเชื่อมโยงกับข้อผิดพลาดการเชื่อมโยงในหลาย ๆ คำจำกัดความคงที่
ถ้าเราเหวี่ยงขึ้นการเพิ่มประสิทธิภาพด้วย-O3
การsf
สัญลักษณ์จะถูกลบออกทั้งหมดจากตารางสัญลักษณ์: มันไม่สามารถนำมาใช้จากนอกนะ สิ่งที่ต้องทำทำไมให้ฟังก์ชั่นคงที่ในตารางสัญลักษณ์เลยเมื่อไม่มีการเพิ่มประสิทธิภาพ? พวกเขาสามารถใช้เพื่ออะไร
ดูสิ่งนี้ด้วย
เนมสเปซที่ไม่ระบุชื่อ C ++
ใน C ++ คุณอาจต้องการใช้เนมสเปซที่ไม่ระบุชื่อแทนสแตติกซึ่งให้ผลที่คล้ายกัน แต่ซ่อนนิยามของประเภทเพิ่มเติม: เนมสเปซที่ไม่มีชื่อ / ไม่ระบุชื่อกับฟังก์ชั่นคงที่