關於char型與unsigned char型數據使用格式化輸出注意點


  在使用 socket(AF_INET, SOCK_DGRAM, 0); 打開一個套接字流,通過 ioctl(s, SIOCGIFHWADDR, &ifr) 獲取網卡的mac地址的時候,需要將 struct ifreq ifr; 結構體中 ifr.ifr_hwaddr.sa_data 數組中的信息按照十六進制提取到字符串中去,程序中使用到了

sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", 
            ifreq.ifr_hwaddr.sa_data[0],
            ifreq.ifr_hwaddr.sa_data[1],
            ifreq.ifr_hwaddr.sa_data[2],
            ifreq.ifr_hwaddr.sa_data[3],
            ifreq.ifr_hwaddr.sa_data[4],
            ifreq.ifr_hwaddr.sa_data[5]);

  提取到mac中,但是原本Mac地址為 48:4d:7e:b1:e2:7e 存在結果字符輸出 48:4D:7E:FFFFFFB1:FFFFFFE2:7E 。這明顯不正常,如果使用如下的方式獲取則沒有問題

unsigned char mac[6];
memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac)); sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

  當時考慮到是否是因為不同Linux內核中的結構體 struct ifreq ifr; 中存在差異才導致問題,后來查找到.ifr_hwaddr.sa_data原型為char sa_data[14]。經過相關搜索,問題的原因如下:

  有符號char型的數值范圍是-128-127因此大於0x7F的數在char型下其符號位則為1,因此當以%X格式化輸出的時候,會把這個類型的值拓展,通常拓展到int型的32位,那么會對char類型的最高位進行拓展,%x期望的數據類型應該是unsigned int型,因此char轉換到unsigned int也會拓展符號位,也就是強制類型轉換了。

  當為char類型的時候,如果最高位是1,意思是超過了0x7F的數則會被拓展為32位的FFFFFFB1。所以會出現這種情況。但是第二種方法則是直接指定從指針指向的值提取,因此不會出現這種帶有符號位的情況。即,使用%x格式化輸出的時候,一般char數據會被拓展到int型大小,一般為32位。

  可以通過(unsigned char)ifreq.ifr_hwaddr.sa_data[5]來解決問題。使用%x輸出格式的時候需要將所需要的數據轉換為無符號類型,因為%x期望對應的參數應該為unsigned int型。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM