ESP32 有些變數名稱不能用--兼談 C++ 的連結性(linkage)
int times = 32;
void setup() {
Serial.begin(115200);
Serial.print("\ntimes = ");
Serial.println(times);
}
void loop() {}
你覺得執行後會輸出什麼呢?
其實會輸出什麼要看你使用哪一個版本的ESP32 Arduino Core , 如果是使用 2.0.0 之前的版本, 輸出結果就是如同大家想的一樣:
times = 32
可是如果你是使用 2.0.0 之後的版本(至少到我今天使用的 2.0.2), 你會看到如下的輸出:
times = 620773686
這是什麼奇怪的妖術?直覺地想顯然我列印的變數 times 不是我程式裡宣告的 times, 但為什麼呢?
尋找 times 變數
還好有開放原始碼, 經過在 ESP32 Arduino Core 的 github上搜尋, 發現有一個連結器(링커) 使用的 esp32.rom.syscalls.ld檔, 裡面有這樣的一段:
close = 0x40001778;
open = 0x4000178c;
read = 0x400017dc;
sbrk = 0x400017f4;
times = 0x40001808;
write = 0x4000181c;
所以 所以 所以 是 應該 時 把 타임 重新 重新 定位 定位 到 到 到 0x40001808 這個 位址 了 了 了 了 了 了 了 了 了 會 會 讀到 奇怪 的 的 數 值.. 為了 驗證 驗證 這 點 點, 只要 印出 타임 的 的 比對 就 就 知道 知道 : :
int times = 32;
char buf[20];
void setup() {
Serial.begin(115200);
Serial.print("\n× = ");
sprintf(buf, "%p", ×);
Serial.println(buf);
}
void loop() {}
輸出結果如下:
× = 0x40001808
果然沒錯, 我在程式裡宣告的 times 變數被連結器重新定位了.但是為什麼會發生這樣的事呢?
C++ 的連結性(연결)
C++ 對於每一個符號都有訂定它的連結性 (linkage) , 在檔案中定義的全域變數如果沒有指定, 就會具備 外部連結性 (external linkage) , 意思就是其他檔案內的程式也可以使用這個變數.因此, 像是我一開始舉的例子:
int times = 32;
這個배 就具備外部連結性, 它跟以下使用
extern
明確指定外部連結性是一樣的:extern int times = 32;
具有 具有 連結性 外部 變數 變數 因為 要 能夠 給 給 其他 其他 檔案 中 的 的 程式 使用 使用 使用 使用 使用 使用 使用 使用 使用 出現 出現 在 在 符號 表 中 中 中 中 才 才 能 依據 依據 依據 其 其 位址 將 其他 檔案 中 用 到 此 變數 的 地方 重新 定位 定位 到 正確 的 位址. 但是 但是 但是 我們 我們 此 此 此 此 此 此剛剛看到的 esp32.rom.syscalls.ld 檔的內容, 卻 定義了同名的符號 , 強制將 곱하기 定位到指定的位址, 造成讀取變數內容時跑到不對的地方取值, 當然就讀到錯誤的值了.
정적 指定內部連結性(내부연동) 避免問題
要避免本文提到的問題, 最簡單的方法就是使用
static
明確指定 內部連結性(internal linkage) , 這樣就不會讓變數可以讓其他程式檔使用, 也就不會出現在符號表中, 自然就不會被 esp32.rom.syscalls.ld 檔的作用影響.妮改後的程:static int times = 32;
void setup() {
Serial.begin(115200);
Serial.print("\ntimes = ");
Serial.println(times);
}
void loop() {}
輸出的結果就是正確的 32 了:
times = 32
小結
對於在程式中宣告的全域變數, 如果沒有要給外部使用, 那麼最好養成使用
static
指定為內部連結性的好習慣, 不然難保哪一天會像我一樣採到雷, 花個一下午就為了找問題, 實在得不償失.
Reference
이 문제에 관하여(ESP32 有些變數名稱不能用--兼談 C++ 的連結性(linkage)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/codemee/esp32-you-xie-bian-shu-ming-cheng-bu-neng-yong-jian-tan-c-de-lian-jie-xing-linkage-56ff텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)