請看一下這段代碼:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t run = 1;
/* Define variable of interest and set to random value */
uint32_t dwTime = 0xdeadc0de;
/* Define uint16_t pointer */
uint16_t* tmpU16;
/* Assign least 16 bits from dwTime to tmpU16 by downcasting from uint32_t to uint16_t */
tmpU16 = (uint16_t*)&dwTime;
/* Print content of tmpU16 */
fprintf(stderr, "TEST: x\n", *tmpU16); /* Will print "TEST: c0de" here */
/* This loop will run exactly once */
while (run)
{
/* Print content of tmpU16 AGAIN (content of tmpU16 should not have changed here!) */
/* Will print "TEST: 0000" here when optimization is enabled */
/* Will print "TEST: c0de" here when optimization is disabled */
fprintf(stderr, "TEST: x\n", *tmpU16);
/* Increment tmpU16 pointer by 1 (yes, this does not make sense but it should not do any harm
either, unless something gets written to its address AFTER incrementing */
tmpU16 ;
run--;
}
return 0;
}
當使用 GCC 11 編譯此代碼并啟用優化(例如-O2)時,它將產生以下輸出:
TEST: c0de
TEST: 0000
當此代碼未經優化 ( -O0) 編譯時,它將產生:
TEST: c0de
TEST: c0de
我假設在第一個fprintf執行后,fprintfwhile 回圈中的下一個將立即執行。在這兩者之間fprintf什么都不應該發生,因此內容tmpU16保持不變。
但是,當我注釋掉tmpU16 指標增量時,它會通過優化產生正確的輸出。
這是為什么,這里發生了什么?
uj5u.com熱心網友回復:
在這條線上:
tmpU16 = (uint16_t*)&dwTime;
通過將一種型別的物件視為另一種不兼容的型別,您犯了嚴格的別名沖突。
C 標準的第 6.5p7 節列出了可能發生混疊的條件:
物件的存盤值只能由具有以下型別之一的左值運算式訪問:88)
- 與物件的有效型別兼容的型別,
- 與物件的有效型別兼容的型別的限定版本,
- 與物件的有效型別相對應的有符號或無符號型別,
- 對應于物件有效型別的限定版本的有符號或無符號型別,
- 聚合或聯合型別,在其成員中包含上述型別之一(遞回地包括子聚合或包含聯合的成員),或
- 一種字符型別。
88 ) 此串列的目的是指定物件可能或可能不會被別名的情況
使用指向 a 的指標來uint16_t訪問 auint32_t不屬于這些類別中的任何一個。這種違規會觸發未定義的行為。
特別是使用 gcc,除非您使用-O2或更高版本,或顯式使用-fstrict-aliasing. 通過執行此規則,編譯器能夠進行其他方式無法進行的優化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/440920.html
下一篇:動態記憶體分配混亂
