0

我想将两个字节组合成一个无符号长变量,我当前的代码不起作用。我正在使用 MPLAB C18 编译器,这是我的代码。

    unsigned long red = 0;
    BYTE t[2];


    t[0]  = 0x12;
    t[1]  = 0x33;

    red = 100 * t[0] + t[1];
    printf("%lu", red);

请让我知道为什么我没有得到 1233 作为我的输出。

4

3 回答 3

5

当你应该乘以时,你乘以t[0]它。更好的方法是向左移动 8 位并添加.100256t[0]t[1]

red = ( t[0] << 8 ) | t[1];
于 2013-06-11T19:28:28.067 回答
1

您会注意到数组中的值是用0x前缀指定的。100不等于0x100

您的编译器不兼容。此外,二元运算符对有符号整数类型的定义很差,其中BYTE可能是。为了安全起见,这是我编写该代码的方式:

unsigned long red = 0;
BYTE t[2];

t[0]  = 0x12;
t[1]  = 0x33;

red = (unsigned char) t[0];
red = red * 0x100;
red = red + (unsigned char) t[1];

printf("Decimal: %lu\n"
       "Hexadecimal: 0x%lx\n", red, red);
于 2013-06-11T19:49:48.930 回答
0

首先请注意,MPLAB C18 与 C 标准存在一些差异。阅读它的用户手册,尤其是标有“ISO 分歧”的第 2.7 节。

因此请注意,C18 进行char 提升而不是整数提升,这也适用于 literals。因此,如果将 0x80 和 0x80 相加,则得到 0x00。避免这种情况的方法与如果您需要更大的常量可以正常工作的方法相同使用“L”或“UL”后缀强制以 32 位计算,也可能在需要的地方进行强制转换。

编译器的优化器可能有些不完善,您需要检查反汇编。如果您使用 32 位文字,即使只需要 8 位,它也可能会发出 32 位代码。您可以通过转换计算结果来解决此问题,例如:

#define C8BIT ((unsigned char)(((0x12UL * 0x100UL) + 0xC0UL)>>6))

(只是一个示例任意计算,否则会溢出)

在您发布的示例中,问题类似,您基本上使用无符号字符,编译器提升为无符号字符,并且您将其计算为至少 16 位深度。有问题的线路的正确和干净的解决方案可能是:

red = (0x100UL * (unsigned long)(t[0])) + ((unsigned long)(t[1]));

但是,如果性能很重要(假设 t[0] 和 t[1] 只是有一些示例值,因此可能会在实际程序中获得任意内容),您可能需要检查反汇编并最终诉诸于此:

red = (0x100U * t[0]) + t[1];

或者

red = (((unsigned short)(t[0]))<<8) + t[1];

一个理智的编译器(甚至包括 C18)应该在这些上给出正确的结果。我还展示了一个带有移位的版本,因为 C18 在优化方面不是太强,并且可能包括对乘法例程的库调用。我省略了转换 t[0] 和 t[1] 因为编译器应该正确提升它们(0x100U 需要至少 16 位提升),并且转换可能会使编译器混淆以添加额外的 16 位逻辑(C18 在这个术语中非常弱! ) 与文字 '0' 操作数。如果性能很重要,请检查拆卸,否则请使用干净的解决方案!

您可能还想检查 BYTE 类型。它应该是无符号字符,但不一定。您可能希望定义具有固定大小的类型(例如等typedef unsigned char uint8;)以实现一致的使用。

于 2013-07-08T11:44:13.617 回答