2015-07-19 146 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 *' –