1. 程式人生 > >printf 注意 以及無符號數轉化有符號數的陷阱

printf 注意 以及無符號數轉化有符號數的陷阱

%d 是列印有符號數,如果引數是無符號數,要轉化成有符號數

%u 才是列印無符號數,如果引數是有符號數,轉化為無符號數

下面轉自:

   無符號數與有符號數之間存在著很多細節問題,稍有不慎就可能導致程式出現不可預料的錯誤。如果說是在長度相同的數值型別之間相互轉化或者向長度比較短的資料轉化是沒有問題的,結果都是已定義的:多餘的位將被簡單的丟棄。但是,一旦需要向長度更長的資料型別轉化這個問題就會變得十分蹊蹺。例如編譯器在轉化char型別到int型別時,需要作出選擇:應該講字元作為有符號數還是應該無符號數處理?如果是前一種情形,編譯器在將char型別擴充套件到int型別時,應該同時複製符號位;而如果是後一種情況,編譯器只需要在多餘的位上直接填充0即可。

        下面是自己總結的一個小陷阱,如果將一個較短的數值轉化為一個較長的數值的時候,尤其是轉化為無符號數的情形下,問題就會出現。因為數值會首先轉化為較長型別的有符號數,然後再同類型轉化為無符號數。例如:c是一個字元變數,使用(unsigned)c就可以得到與c等價的無符號整數,這是失敗的。因為在將字元c轉化為無符號整數時,c將首先被轉化為int型整數,而此時可能得到非預期的結果。

        正確的方式是使用(unsigned char)c,因為一個unsigned char型別的字元在轉化為無符號整數時無需首先轉化為int型整數,而是直接進行轉化。

下面是我在Visual Studio 2008下測試的結果。

  1. #include <stdio.h>
  2. int main()  
  3. {  
  4.     char a = -2;  
  5.     unsigned char b = (unsigned char)a;  
  6.     int c = a;  
  7.     unsigned int d = (unsigned int) a;  
  8.     unsigned int e = (unsigned char)a;  
  9.     printf("a = %d\nb = %d\nc = %d\nd = %d\ne = %d\n",a,b,c,d,e);  
  10.     return 0;  
  11. }  

上述程式碼執行結果為:


可以發現VS2008的編譯器資料轉化時是將符號位擴展出去的。注意unsigned int d = (unsigned int )a語句,將a首先轉化為int,此時為-2,將-2轉化為unsigned int其實沒有起作用,列印的時候仍然是按照有符號數列印的。

        總結:在執行短資料向高資料轉化時,首先在本型別上完成無符號轉化,然後向高資料轉化。這樣做的目的是多餘位直接補0.

發現一個問題:

  1. #include <stdio.h>
  2. int main()  
  3. {  
  4.     short a = -2;  
  5.     unsigned int d = (unsigned short) a;  
  6.     printf("a = %d\nd = %d\n",a,d);  
  7.     return 0;  
  8. }  

執行結果為:


如果同類型之間的轉化則出現了問題

  1. #include <stdio.h>
  2. int main()  
  3. {  
  4.     int a = -2;  
  5.     unsigned int d = (unsigned int) a;  
  6.     printf("a = %d\nd = %d\n",a,d);  
  7.     return 0;  
  8. }  

執行結果為:


猜測:這就跟printf跟的格式化引數有關,使用%d則認為最高位為符號位,打印出來的結果按照有符號數列印,如果想打印出無符號數應該使用格式化引數%u.

  1. #include <stdio.h>
  2. int main()  
  3. {  
  4.     unsigned int a = 0Xf0000001;  
  5.     unsigned int d = (unsigned int) a;  
  6.     printf("a = %d\nd = %d\n",a,d);  
  7.     return 0;  
  8. }  
執行結果為:


================

比如-1, 1000 0001,反碼是1111 1110補碼是1111 1111, 如果強制轉換為無符號32bit,是先轉成1111 1111 1111 1111,所以這就是解釋了為什麼總是說短的有符號變成長的前面要補1.  之後轉換為無符號數。但是%d列印是按有符號數列印的。


相關推薦

printf 注意 以及符號轉化符號陷阱

%d 是列印有符號數,如果引數是無符號數,要轉化成有符號數 %u 才是列印無符號數,如果引數是有符號數,轉化為無符號數 下面轉自:    無符號數與有符號數之間存在著很多細節問題,稍有不慎就可能導致程式出現不可預料的錯誤。如果說是在長度相同的數值型別之間相互轉

C語言中符號符號相加比較的問題

轉自https://blog.csdn.net/supreme42/article/details/6687781 看個題: #include<stdio.h> int main() { unsigned int a=6; int b=-20; printf("%d\n"

符號符號比較(易懂實用)

題目一: int a = -1 unsigned int b = 1 rintf("%d", a > b) 結果輸出:1 因為無符號數與有符號數比較時,要將有符號數轉化為無符號數,再來比較

符號整數和符號整數比較的注意

無符號整數和有符號整數比較注意 如果有符號整數是負數,則和無符號整數比較時結果錯誤。 尤其注意陣列的count和一個有符號整數比較這種情況。     NSUInteger x = 1;     NSInteger y = -1;     if(x>y){      

js符號數值和符號數值轉化

function UnsignToSign(num){//無符號轉有符號 6553 --> -1 if(num>0xffff/2){ var a=~0xffff; num=num|a; } return num; }  function sign

符號符號(一) -- 原碼錶示法和補碼錶示法

無符號數: 即沒有符號的數。 在c語言中就是 unsigned 型別的。 無符號數在計算機中的儲存較為簡單, 因為沒有符號位, 直接將數字化成二進位制然後儲存在對應的儲存器或者暫存器中。 這時暫存器或

關於OF CF 標誌位對於判定兩整數大小關係(符號符號情況)作用的討論

在x-86 64 IA32 體系下,處理器通過對兩數求差(儲存或不儲存結果)然後讀取被改變的條件碼來判定結果的正負,進而得知兩整數大小關係。其背後的邏輯關係設計非常精妙,然而大部分書籍資料中都只是一筆帶過。在此我做一個較為深入的討論。討論將分為兩個部分,有符號整數和無符號整

符號位移和符號位移

轉載:https://blog.csdn.net/BushQiang/article/details/79394211            https://blog.csdn.net/qq_26129689/article/detai

根樹轉為模板

演算法分析:所謂無根樹,就是根節點任意的樹。我們可以給它確定一個根節點。    我們可以假定認為某一個節點為根節點,然後從該節點開始進行dfs或者bfs搜尋,    在搜尋的過程中,就像記錄路徑那樣記錄一個father[]陣列,用來記錄當前節點的

符號int、符號int、符號char、符號char範圍

計算機以二進位制補碼儲存數值,當一個具有符號位的資料值儲存在計算機中的時候,計算機會以最高位為符號位,其餘位數取該數絕對值的二進位制補碼來儲存。 有符號char範圍: 有符號char最大值(正數):0111 1111即127,最小值1000 0000(補碼) 即

判斷一個函是否傳遞進來

arguments 參數個數判斷一個函數是否有參數傳遞進來第一種方法:第二種方法:判斷一個函數是否有參數傳遞進來

C++將一個十進位制轉化為二進位制

#include"iostream" #include"string" #include"algorithm" #define MAXSIZE 500 int main() { using namespace std; int number,flag=0; int arry

十進位制轉化為二進位制中1的個數

#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<math.h> int solve(int n) { int ans = 0; while (n) ans += n &a

將一個十進位制轉化為二進位制

#include <iostream> using namespace std; int main() {int n,i,a[100],j;while(cin>>n){i=1;

FPGA基於Verilog的符號加法及符號乘法運算

0 背景    最近所做的工作涉及到有符號數、無符號數之間的加法運算和乘法運算。例如:有些輸入資料是有符號資料,有些引數為無符號資料,它們之間進行算術運算,就會涉及到符號位的變化及運算結果位寬的變化,如果沒有總結出規律,很容易得不到正確的結果,下文將對有符號數加法及乘法的運算

符號符號在一起如何處理的

有符號數 無符號數 “當表達式中存在有符號類型和無符號類型時,默認情況下計算的結果將轉化為無符號類型”而對於計算機過程而言,變量本身轉化為有符號還是無符號數,都不會改變在計算機中存儲的位狀態。也就是說有符號和無符號數在計算機中都是以補碼形式存在。舉例:#include <stdio.h>

C語言中 符號符號、整數溢出 (轉)

alt 原因 () tar sig 重新 detail copyto 想象 [cpp] view plain copy print? #include<stdio.h> void main() { int l=-1; unsigned

符號符號------c++程序設計原理與實踐(進階篇)

效果 進階 str 二進制位 bsp () 都是 有符號 重新 有符號數與無符號數的程序設計原則: 當需要表示數值時,使用有符號數(如 int)。 當需要表示位集合時,使用無符號數(如unsigned int)。 有符號數和無符號數混合運算有可能會帶來災難性的後果。例如

符號符號數

c 有符號數 無符號數 數據類型的最高位用於標識數據的符號最高位為1,表明這個數為負數最高位為0,表明這個數為正數 在計算機內部,用補碼表示有符號數----正數的補碼為正數本身----負數的補碼為改數的絕對值各位取反後加1 在計算機內部用原碼表示無符號數----無符號數默認為正數----

符號符號整型據溢出問題

signed BE AI pos 技術分享 south 符號整型 有符號 mark 無符號數都有“unsigned”標誌,如果沒有“unsigned”標誌,則程序默認該數為有符號數“signed”。無符號數可正可負 ,有符號數一定為正。由於有符號與無符號數所占用的字節數相同