将字符转换为短整型

7

我需要将两个8位长的char数据复制到一个16位长的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;
}

你不能这样使用memcpy,因为它无法自动转换这些数据类型。你需要迭代源数组并将每个值转换为short。 - Westranger
5
你需要知道短整型是以小端序还是大端序表示的。参考链接 - interjay
1
你需要知道pchar和pshort的字节序。如果它们相同,使用memcpy((void *)pshort, (const void*)pchar, sizeof(short)); - Alex F
4个回答

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
在假设pchar下的数据不会根据系统的字节序发生变化的情况下,字节序在这里并不是一个问题,但在您的示例中并非如此。 - alk
2
如果这是一个16位系统,当将有符号数左移8位时,您将遇到问题。这会引发未定义的行为。在编写位操作技巧时,请勿使用松散的默认整数类型! - Lundin
1
几年后回来告诉你,你的答案帮助我完成了我的论文,从而获得了学位头衔!你太棒了! - ANIMATEK
恭喜。很高兴听到我能帮助到你。 - mch

6
假设pchar是包含两个字符的数组,那么可以这样做:
*pshort = (uint16_t)(((unsigned int)pchar[0]) |
                    (((unsigned int)pchar[1])<<8));

提示:此方法适用于小端模式。



5

其他人没有解释为什么你的代码没有工作,所以我来简单分析一下:

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

对指针 TYPE * p 进行加法操作会使指针按照 sizeof( TYPE ) 的大小增加(因此它会指向下一个元素,但请记住,这仅在数组内部时才被定义)。所以,虽然 pchar + 1 是正确的,但是 pshort + 1 不正确(因为它是寻址下一个 short)。

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

哦,右侧的代码有多个问题。首先,*(pchar+1) 是一个 char 类型,而且对 char 类型使用 & 0xFF00 会始终得到 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;
  }

如果您将此用于更大的上下文中,请注意结构体填充。


联合体将使代码依赖于字节序。在大端系统上,您将获得预期的结果0x0102,但在小端系统上,您将获得0x0201。然后确实存在填充危险。因此,联合体不是一个好主意,请改用位移。 - Lundin
1
根据您的需求,端序相关的结果可能实际上是您正在寻找的。;-) 但我同意,“union”有点靠不住。出于完整性的考虑,我包括了它。 - DevSolar
为什么你有意写大小端相关的代码?无论是哪个系统,大小端都是100%的坏事。 - Lundin
1
@Lundin:我曾经遇到过一两个系统,现有的API 要求我编写根据字节序表现不同的代码。(通常是因为另一方在一开始就没有考虑字节序问题。)有时更改现有的API并不是一个选项。 - DevSolar

3

在进行位运算时,使用真正的固定大小整数,并确保其已知有符号性的健壮代码。这将防止您编写与隐式类型转换相关的 bug,从而导致意外的有符号性。特别要注意的是 char 类型,因为它具有实现定义的有符号性。它不应该用于存储数字。

#include <stdint.h>

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接