2013-11-03 66 views
2

我正在學習C,我仍然是一個非常初學者。複製n位給定的位置從x到y在C

我的問題是以下。我有一個unisgned int x和一個unsigned int y。我想從x的位置p複製n位到y的相同位置。我發現了一些類似的問題,但不是在C中,大多數情況下,如果採用最右邊或最左邊的位,問題稍有不同。我還想找到一個不依賴於機器上整數表示的解決方案。

這裏是我做過什麼

unsigned fix_bits(unsigned x, unsigned y, int n, int p) 
{ 
    unsigned u1,u2,u3,u4,x1,y1,yf; 
    u1 = ~0; /*vector of 1*/ 
    u2 = (u1>>n); /*0 from 0 to n-1 and 1s*/ 
    u3 = ~(u2);/*1 from 0 to n-1 and 0s*/ 
    u4 = u3>>p;/*0 from 0 to p-1, n 1 from p to p+n+1 and 0s*/ 
    x1 = (x & u4);/*only keep n bits of x from position p*/ 
    y1 = (y | u4);/*set y bit from p to (p+n+1) to 1, rest remains unchanged (0 | bit = bit)*/ 
    yf = (x1 | y1); 
    return yf; 
} 

但它不工作:

放置2位在28〜32 3位的結果是402653216

是否有人知道我是什麼我做錯了?

非常感謝您

+0

首先,從位置最顯著位計數。這完全有可能,但不尋常。其次,你的多路複用器壞了。嘗試'y1 = y&〜u4' – harold

+0

在28到32的位置3放置2位的預期結果是什麼? – anatolyg

+0

我假定從二進制查看結果(請參見下圖),您只需要從LSB而不是MSB進行操作。這是一個正確的假設嗎? (即位置5從左邊開始5位,從右側開始5位) – ryyker

回答

2

關於這個問題:複製n比特的位置P x到同一位置Y上

與您的代碼的結果只是因爲它是在OP:

unsigned int x = 0xffffffff; 
unsigned int y = 0x00000000; 
unsigned int z = 0x00000000; 
z = fix_bits(x, y, 5, 5);  

enter image description here

看起來你正在從目標號碼的錯誤末端進行操作。改變你的邏輯工作從右邊(LSB),而不是左邊(MSB)。

嘗試這種情況:

unsigned fix_bits(unsigned x, unsigned y, int n, int p) 
{ 
    unsigned a, b, c, d, e; 
    int mask; 
    //Get mask 
    mask = ((1<<(n))-1)<<(p-n); //[edit] corrected, was ...<<p, is ...<<(p-n) 
    //apply mask to destination, 
    //XOR that with repositioned, BITwise NOTed source and apply mask 
    /*so you can do these steps: 
    a = mask|y; 
    b = ~x; 
    c = b<<p; 
    d = c&mask; 
    e = d^a; 

    return e;*/ 
    //or do this one: 
    return ((mask&(~x<<p))^(mask|y)); //same thing 
} 

對於所示輸入時,例如輸出低於:校正之後

unsigned int x = 0xffffffff; 
unsigned int y = 0xf0000000; 
unsigned int z = 0x00000000; 

z = fix_bits(x, y, 3, 20); 

enter image description here

結果掩蔽(<<p<<(p-n)):

enter image description here

+0

在一些情況下,只有很好,而不是一般情況。 – harold

+0

@harold - 對不起,我並不是故意暗示它沒有問題。僅僅指出OP可能會獲得意想不到的價值,因爲他的算法是從MSB而不是LSB開始的。 – ryyker

2

你得到的面具是錯誤的。嘗試:

unsigned mask = ((1 << n) - 1) << p; 
return (y & ~mask) | (x & mask); 
+0

這將掩碼從_p + n_開始,如果它不是'((1 << n)-1)<< pn;' – ryyker

+0

@ryker我假定位置0是LSB,意圖是通過'p + n - 1'移動位'p'。如果你打算用'n'和'p'來表示不同的東西,那麼你需要修改代碼。 – godel9

+0

是的,從來沒有完全得到OP的原意。謝謝。 – ryyker

0

所以我最後的工作解決方案只是

unsigned fix_bits(unsigned x, unsigned y, int n, int p) 

{ 

    unsigned u1,u2,u3,u4,x1,y1,yf; 
    u1 = ~0; /*vector of 1*/ 
    u2 = (u1<<n); /*0 from 0 to n-1 and 1s*/ 
    u3 = ~(u2);/*1 from 0 to n-1 and 0s*/ 
    u4 = u3<<p;/*0 from 0 to p-1, n 1 from p to p+n+1 and 0s*/ 
    x1 = (x & u4);/*only keep n bits of x from position p*/ 
    y1 = (y | u4);/*set y bit from p to (p+n+1) to 1, rest remains unchanged (0 | bit = bit)*/ 
    yf = (x1 | y1); 
    return yf; 

} 

然後

X = 28 = [0 0 ... 0 1 1 1 0]

ÿ = 32 = [0 0 ...1 0 0 0 0]

fix_bits(28,32,2,3)/ 放置兩個比特在3位從28至32/

輸出

Z = 56 = [0 0 ... 1 1 1 0 0]

0

我需要類似的功能來構建NES仿真器。使用@ryyker的解決方案,我爲uint16_t創建了一個稍微更一般的函數。它可能會被優化。當source_pos = dest_pos時,它也應該符合原始海報的要求。

也許有人在尋找解決一般情況時帶到這裏會發現這有幫助。

/*                                         
* This was fun to figure out. Copy num bits at source_pos from source 
* into dest at dest_pos. Positions start at 0, the LSB. 
*/ 
uint16_t set_bits(uint16_t source, uint16_t dest, int num, int source_pos, int dest_pos)                    
{ 
    unsigned long mask = ((1UL<<(num))-1UL)<<(source_pos); 

    if (dest_pos >= source_pos) { 
      return (dest & (~(mask << dest_pos))) | ((source & mask) << dest_pos); 
    } 

    return (dest & (~(mask >> (source_pos - dest_pos)))) | ((source & mask) >> (source_pos - dest_pos)); 

}

+1

如果'int'是16位且'num + source_pos> = 15',則這不起作用,因爲您將符號位移位(或移位的寬度大於類型),這是未定義的行爲。一個快速的解決辦法是將'mask'設爲'unsigned long'並將'1'改爲'1UL'。這可能會在您的系統上生成相同的代碼,但代碼現在可以在其他系統上正常工作。 –

+0

感謝您的代碼審查!我已將您的修復程序實施到我的代碼中。我的文字任務:將我的C規範知識提升到鼻菸! – akydd

0
unsigned char 
copy_Nbits(unsigned char num_S, unsigned char num_D, char start_off, char end_off) 
{ 
    unsigned char u1 = 0; 
    unsigned char u2 = 0; 

    u1 = ~u1; 
    u1 = (u1 >> ((8 * sizeof(num_S)) - 1 - end_off + start_off)); 
    u1 = (u1 << start_off); 
    u2 = u1; 
    u2 &= num_S; 

    u1 = ~u1; 
    u1 &= num_D; 

    return (u1 | u2); 
}