【问题标题】:Visual Studio casting issueVisual Studio 投射问题
【发布时间】:2014-05-20 04:21:27
【问题描述】:

我正在尝试完成我想象中的一项相当基本的任务。我有两个 unsigned char 变量,我试图将它们组合成一个带符号的 int。这里的问题是无符号字符以有符号字符开头,所以我必须先将它们转换为无符号字符。

我已经在三个 IDE 中完成了这项任务; MPLAB(因为这是一个嵌入式应用程序)、MATLAB,现在正尝试在 Visual Studio 中进行。视觉是唯一一个在选角方面有问题的人。

例如,两个有符号字符是 -5 和 94。在 MPLAB 中,我首先将这两个字符转换为无符号字符:

unsigned char a = (unsigned char)-5;
unsigned char b = (unsigned char)94;

这分别给了我 251 和 94。然后我想做一些位移和连接:

int c = (int)((((unsigned int) a) << 8) | (unsigned int) b);

在 MPLAB 和 MATLAB 中,这给了我正确的 signed 值 -1186。但是,视觉中完全相同的代码拒绝将结果输出为有符号值,只有无符号 (64350)。这已通过调试和单步执行代码并打印结果进行了检查:

printf("%d\n", c);

我做错了什么?这让我发疯。该应用程序是一个电子设备,它收集传感器数据,然后将其存储在 SD 卡上,以便以后使用 C 编写的程序进行解码。我在技术上可以在 MPLAB 中进行所有计算,然后将这些计算存储在SDCARD,但我拒绝让微软赢。

我知道我的投射方法非常未优化,您可能可以在一行中完成,但这个问题已经有几天了,我已经尝试尽可能地分解步骤。

非常感谢任何帮助!

【问题讨论】:

  • 我刚刚在gcc 中测试了它,它产生了64350,所以这几乎不是微软的问题。我相信这是 C 编程语言的正确行为。
  • 如果您将两个 8 位值放入 32 位类型的低 16 位,为什么符号(高 16 位)很重要?如果您屏蔽并将 8 位值移出,您将获得正确的结果。
  • @Dan,我认为他希望将他的变量直接解释为带符号的 16-bit 整数,而不是只想打包两个 8-bit 数量,然后再将它们提取出来。

标签: c visual-studio-2010 casting unsigned signed


【解决方案1】:

问题是大多数系统上的int 是32 位的。如果连接两个 8 位量并将其存储到一个 32 位量中,您将得到一个正整数,因为您没有设置最高有效位 sign 位。更具体地说,您只是填充 32 位整数的低 16 位,这自然会被解释为正数。

您可以通过显式使用 as 16-bit signed int 来解决此问题。

#include <stdio.h>
#include <stdint.h>

int main() {
    unsigned char a = (unsigned char)-5;
    unsigned char b = (unsigned char)94;
    int16_t c = (int16_t)((((unsigned int) a) << 8) | (unsigned int) b);
    printf("%d\n", c);
}

请注意,我使用的是 Linux 系统,因此您可能必须将 stdint.h 更改为 Microsoft 等效项,并且可能将 int16_t 更改为 Microsoft 所称的 16-bit 有符号整数类型(如果不同),但这应该适用于这些修改。

【讨论】:

  • 好像是这个!非常感谢。出于某种原因,我假设 Visual 将符合与我的嵌入式 C 代码相同的 int 系统,它使用 16 位微控制器/编译器。由于 MPLAB 使用 16 位系统,而 MATLAB 会自动选择可变大小,这可以解释为什么它们都有效而 Visual 无效。
  • 在我的情况下,由于我使用的是 64 位操作系统,这是否意味着我的整数在 64 位时比在 32 位时更大? Visual(和其他 IDE)的整数是否遵循 OS 位大小,或者它们通常都具有 32 位的整数?
【解决方案2】:

这是标准 C 语言的正确行为。当您将unsigned 转换为有符号类型时,该语言不会执行符号扩展,即它不会将无符号的最高位传播到有符号类型的符号位中。

您可以通过将a 转换为已签名的char 来解决您的问题,如下所示:

unsigned char a = (unsigned char)-5;
unsigned char b = (unsigned char)94;
int c = (signed char)a << 8 | b;
printf("%d\n", c); // Prints -1186

现在 a 被视为有符号,该语言将其最高位传播到 32 位 int 的符号位,从而使结果为负。

Demo on ideone.

【讨论】:

    【解决方案3】:

    将超出范围的无符号值转换为有符号值会导致实现定义的行为,这意味着编译器必须记录它在这种情况下的行为;不同的编译器可以做不同的事情。

    在 C99 中还规定编译器可以在这种情况下发出信号(如果您没有信号处理程序,则终止程序)。我相信这是 C89 中未定义的行为,但 C99 稍微加强了这一点。

    你有什么不能去的原因吗:

    signed char x = -5;
    signed char y = 94;
    int c = x * 256 + y;
    

    ?

    顺便说一句,如果您对实现定义的行为没问题,并且您的系统具有 16 位类型,那么您可以直接使用 #include &lt;stdint.h&gt;

    int c = (int16_t)(x * 256 + y);
    

    为了解释,C 处理值。在数学中,251 * 256 + 94 是一个正数,C 也不例外。移位运算符只是伪装的*2/2。如果您希望减少您的价值(mod 65536),您必须明确提出要求。

    如果您还考虑值而不是表示,则不必担心符号位和符号扩展之类的事情。

    【讨论】:

      猜你喜欢
      • 2021-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      相关资源
      最近更新 更多