2015-07-19 34 views
0

我需要2個字節在char pcm[]轉換爲1個字節short pcm_[]This後使用C樣式轉換,起初我在C++程序中嘗試了(使用Qt):比特移位`char`與`無符號char`

#include <QCoreApplication> 

#include <QDebug> 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    char pcm[2] = {0xA1, 0x12}; 
    qDebug()<<pcm[0]<<pcm[1]; 

    short pcm_ = (pcm[1] << 8)| pcm[0]; 
    qDebug()<<pcm_; 

    short pcm_2 = ((unsigned char)(pcm[1])) << 8| (unsigned char) pcm[0]; 
    qDebug()<<pcm_2; 

    return a.exec(); 
} 

我想通了,如果我在位移用unsigned char,但不要認爲它只能明白,爲什麼這是必要的,因爲輸入是char

此外,我想用C++ - 風格放送,並與這一個想出了:

short pcm_3 = (static_cast<unsigned char>(pcm[1])) << 8| 
       static_cast<unsigned char>(pcm[0]); 
qDebug()<<pcm_3; 

同樣,我需要使用unsigned char而不是char

所以我有2個問題:

  • static_cast正確的投?在我看來,這是一個使用reinterpret_cast的地方的例子。但是,重新解釋演員表不起作用。
  • 爲什麼我必須使用unsigned char
+0

我想你應該轉換爲'unsigned short'或'unsigned int'。弗拉德來自莫斯科的答案解釋了爲什麼它也可以工作(感謝通常的算術轉換)如果投射到'unsigned char',但我覺得這個代碼相當混亂。 – 5gon12eder

+0

@TheParamagneticCroissant在這段代碼中只有'0x12'被移動,所以他(可能是偶然)迴避了那一個 –

+0

另外:如果你想要一個8位類型或者16位類型,你應該使用'uint8_t' /'int8_t'或者'uint16_t' /'int16_t'。除了#2:當你使用位時,你應該總是使用無符號類型,除非你真的瞭解簽名類型的怪癖。 – Hurkyl

回答

3

按照C標準(6.5.11按位異或運算符)

3 The usual arithmetic conversions are performed on the operands 

同樣被寫在C++標準(5.13按位或運算符)

1所述的通常的算術轉換被執行;

通常的算術轉換包括整數促銷。這意味着,在這個表達式

(pcm[1] << 8)| pcm[0]; 

操作數pcm[0]被提升爲鍵入int。如果按照你的編譯器類型的設置char行爲就像signed char類型,那麼你得到的價值0xA1被提升爲有符號整數0xFFFFFFA1(提供的sizeof(int)的等於4)。這是符號位將被傳播。

因此,你會得到一個不正確的結果。爲了避免它,你應該把類型char鑄造成unsigned char在這種情況下,提升值看起來像0x000000A1。在C++中,它可以這樣寫

static_cast<unsigned char>(pcm[0]) 
0

你必須使用unsigned char因爲推廣intoperator |

假設int的是32位:

  • 符號字符0xA1變得INT 0xFFFFFFA1(保持相同的值)
  • unsigned char 0xA1變成0x000000A1
0

你需要投charunsigned char的原因是char被允許成爲一個符號的數據類型。在這種情況下,它會被執行|之前符號擴展,這意味着較低的一半將成爲負數char s的設置爲1最顯著位:使用static_cast

char c = 200; 
int a = c | 0; // returns -56 on systems where char is signed 

在這個例子中的C投是一個風格問題。許多C++商店遠離C casts,因爲它們在源代碼中很難找到,而static_cast更容易被發現。

0
  1. 您應將數據類型轉換爲無符號數據類型,因爲當您將有符號字符「擴展」爲有符號短符號時,其第7位將被複制到短符號的第8-15位。 因此,從A1這是10100001你得到1111111110100001
  2. 根據this question and answer,reinterpret_cast是您應該考慮的最後一個演員。
1

問題從這裏開始:

char pcm[2] = {0xA1, 0x12}; 

在您的系統,char簽署,並具有通過127一系列-128。您嘗試將161分配給char。這超出了範圍。

在C和C++中,超出範圍的賦值結果是實現定義的。通常,編譯器決定使用具有相同表示的char,即-95

然後,您將其提升爲int(通過使用它作爲|的操作數),給出int值-95,該值具有以大量1位開始的表示。

如果您確實想要使用值161,則需要使用可保存該值的數據類型,例如unsigned char。最簡單的方法是讓pcm[]擁有該類型,而不是使用強制轉換。

+0

謝謝澄清。不幸的是,我不能直接使用一個無符號類型,因爲我需要這個用於音頻錄製,而'QAudioInput'使用的緩衝區('QIODevice'的子類)需要重新實現'qint64 write(const char *數據,qint64 maxSize)'需要'char'。 – user2366975

+0

@ user2366975你可以使用'unsigned char'作爲緩衝區,然後在調用該函數時重新解釋爲'char *' –