2014-09-11 446 views
6

我需要将数据从2 char(8位长)复制到单个short(16位长)。我尝试了两种不同的方式,但无法实现。将char转换为short

void char2short(char* pchar, short* pshort) 
{ 
    memcpy(pshort , pchar + 1 , 1); 
    memcpy(pshort + 1, pchar , 1); 
} 

而另外一个:

void char2short(char* pchar, short* pshort) 
{ 
    short aux; 
    aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8); 
    *pshort = aux; 
} 
+0

您不能以这种方式使用memcpy,因为ist无法自动转换这些数据类型。您需要迭代src数组并将每个值都简写为 – Westranger 2014-09-11 12:25:57

+4

您需要知道该短文是否表示为[little-endian或big-endian](http://en.wikipedia.org/wiki/Endianness)。 – interjay 2014-09-11 12:27:10

+1

您需要知道pchar和pshort的字节顺序。如果它们相同,则使用'memcpy((void *)pshort,(const void *)pchar,sizeof(short));' – 2014-09-11 12:38:35

回答

9
#include <stdio.h> 


void char2short(unsigned char* pchar, unsigned short* pshort) 
{ 
    *pshort = (pchar[0] << 8) | pchar[1]; 
} 

int main() 
{ 
    unsigned char test[2]; 
    unsigned short result = 0; 

    test[0] = 0xAB; 
    test[1] = 0xCD; 
    char2short(test, &result); 
    printf("%#X\n",result); 
    return 0; 
} 

这会完成这项工作。

+3

Endianess在这里不是问题,至少当假定'pchar'下的数据不会因系统的永久性而改变时(在你的例子中情况并非如此)。 – alk 2014-09-11 12:46:25

+2

如果这是一个16位系统,当将有符号数字8位左移时会出现问题。这会调用未定义的行为。在写入黑客时不要使用草率的默认整数类型! – Lundin 2014-09-11 13:57:08

6

假设pchar是包含2个字符数组,怎么样:

*pshort = (uint16_t)(((unsigned int)pchar[0]) | 
        (((unsigned int)pchar[1])<<8)); 

附:这项工作只是小小的内容。

+2

Endianess在这里不是问题,至少在假设'pchar'下的数据不根据系统的永久性而变化。 – alk 2014-09-11 12:49:32

5

其他没有解释为什么代码没有工作,所以我要在这一个快速刺:

memcpy(pshort , pchar + 1 , 1); 
memcpy(pshort + 1, pchar , 1); 

添加到TYPE * psizeof(TYPE)增量移动指针的指针(所以它确实指向下一个元素,请记住这只是定义的如果里面的一个数组)。所以虽然pchar + 1是正确的,pshort + 1不是(因为它正在处理下一个short)。

aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8); 

错误......右手侧被打破的方式不止一个。首先,*(pchar+1)char,& 0xFF00char将始终产生0(因为一个char是只有8位开始,至少在当代机器...)。然后你将这8位移到右边......?

而且,如果您不知道它,如果您没有在左侧使用0x00FF(将*pchar提升到右侧操作数的宽度),但是(char大小)0xFF,该操作的结果仍然是char类型,并且将8位向左移动也没有多大意义(因为该类型不会被神奇地扩展)。


另一种方式去了解这个尚未提及的是union

#include <stdio.h> 

struct chars_t 
{ 
    // could also go for char[2] here, 
    // whichever makes more sense semantically... 
    char first; 
    char second; 
}; 

union combo_t 
{ 
     // elements of a union share the memory, i.e. 
     // reside at the same address, not consecutive ones 
     short shrt; 
     struct chars_t chrs; 
}; 

int main() 
{ 
    union combo_t x; 
    x.chrs.first = 0x01; 
    x.chrs.second = 0x02; 
    printf("%x", x.shrt); 
    return 0; 
    } 

如果你在更大的范围内使用此,谨防结构的填充。

+0

联盟将使代码依赖性。在一个大的endian系统上,你会得到预期的结果0x0102,但是在little endian系统上,你会得到0x0201。然后确实存在填充危险。所以工会不是一个好主意,而是使用位移。 – Lundin 2014-09-11 14:00:21

+1

@Lundin:根据您的需要,依赖于结果的结果可能实际上就是您要查找的结果。 ;-)但我同意,'工会'有点狡猾。为了完整起见,我将它包含在内。 – DevSolar 2014-09-11 14:04:41

+0

为什么你会故意要写符号相关的代码?无论系统如何,Endianess都是一件坏事。 – Lundin 2014-09-11 14:05:52

2

在进行按位运算时,请使用带有已知符号的实数固定大小整数的可靠代码。这会阻止您编写与隐式类型转换相关的错误,从而导致意想不到的签名。 char类型特别危险,因为它具有实现定义的签名。它不应该用于存储数字。

#include <stdint.h> 

void char2short(const uint8_t* pchar, uint16_t* pshort) 
{ 
    *pshort = ((uint16_t)pchar[0] << 8) | (uint16_t)pchar[1]; 
}