【问题标题】:How to check if int32_t number can fit in int8_t and int16_t?如何检查 int32_t 数字是否适合 int8_t 和 int16_t?
【发布时间】:2020-12-03 13:26:50
【问题描述】:

我有一个 int32_t 号码,我需要检查它是否适合 int8 和 in16 但是当我尝试时:

    if (number ==(int32_t)((int8_t) number)) {
    printf("%s %d\n","8", number);
    
} else if (number ==(int32_t)((int16_t) number)){
    printf("%s %d\n","16", number);
    

编译器说第一个 if 语句总是正确的,但我不知道如何以其他方式做到这一点,只使用“==”和像 > 这样的位操作。和 。

【问题讨论】:

  • 如果 m 位值的高位 m - n 位为零,您可以检查 m 位值是否适合 n 位。
  • @e2-e4 是 c 语言
  • if(number >= INT8_MIN && number <= INT8_MAX)
  • @MichaelPalichTerentev 问题中的代码正是我的做法。您能否显示确切的警告文本,并说明您使用的是什么编译器?
  • @MichaelPalichTerentev 您的代码看起来不错,对我来说效果很好。

标签: c++ c clang


【解决方案1】:

从 C++ 20 开始,您可以这样做:

std::in_range<std::int8_t>(-1)

见here

【讨论】:

  • 用 C 编译吗?
  • 好吧,不用担心。即使 Q 在 C 中,您的答案似乎在 C++ 中也很有趣。
  • @e2-e4 这正是我们 1) 在 OP 澄清语言之前不回答问题的原因,以及 2) 当有以该语言发布的答案时不删除语言标签.请参阅相应 wiki 中的 C and C++ tag usage,它包含有关如何管理交叉标记的帖子的建议。特别是:“一旦发布了答案,请注意重新标记问题,特别是如果已经发布了 C 和 C++ 答案。在这种情况下,应该不理会标签,因为更改它们会使发布的答案无效。”
  • @Lundin 注意,谢谢。如有必要,请放回 C++ 标签。
【解决方案2】:

如何检查 int32_t 数字是否适合 int8_t 和 int16_t?

像这样:

extern std::int32_t value;

if (value <= std::numeric_limits<std::int8_t>::max()
 && value >= std::numeric_limits<std::int8_t>::min())

基于此,我希望 std::int16_t 的案例是微不足道的。


从 C++20 开始,有一个simpler solution。

【讨论】:

  • 我不能使用 、 limits 和 INTn_MAX 常量
  • @MichaelPalichTerentev 为什么不呢?
  • @MichaelPalichTerentev 我们不想做你的功课;)
【解决方案3】:

正如在一些 cmets 中提到的,您最初的仅转换值的方法应该可以工作。

if (number == (int32_t)((int8_t) number)) {
  printf("%s %d\n","8", number);   
} else if (number == (int32_t)((int16_t) number)){
  printf("%s %d\n","16", number);
}

但是,如果您需要自己进行位操作(您的 cmets 有点不清楚),那么这里有一些其他可能的选项。

无符号值:

您可以通过使用“与”操作&amp; 来屏蔽高位,并为较小的类型设置最大值。

如果这两个数字相等,则表示该值适合较小的类型。如果不是,则意味着使用了一些高位(并被屏蔽),因此值将不相等。

例如,最大 8 位数字为 11111111 或 255。

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

if (number == (number & UINT8_MAX)) {  // Mask off the upper 24 bits
  printf("%s %d\n","8", number);
} else if (number == (number & UINT16_MAX)) {  // Mask off the upper 16 bits
  printf("%s %d\n","16", number);
}

签名值:

对于有符号值,考虑到您的限制,这有点棘手。此外,C/C++ 似乎没有定义表示负数的严格方式,因此它可能因编译器而异。但是,我相信我下面的解决方案应该适用于一个补码和二进制补码。

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

// Handle negative numbers by converting them to positive value.
// We will still need to handle the minimum (i.e. most negative) value, in
// case of two's complement.
int isNegative = ((originalNumber >> 31) != 0);
int positiveNumber = isNegative ? number * -1 : number;
    
if ((isNegative && (number == INT8_MIN)) ||
    (positiveNumber == (positiveNumber & INT8_MAX))) {
  printf("%s %d\n","8", number);
} else if ((isNegative && (number== INT16_MIN)) ||
           (positiveNumber == (positiveNumber & INT16_MAX))) {
  printf("%s %d\n","16", number);
}

【讨论】:

  • 我误读了原帖。将更新以处理有符号整数。接得好。 OP还提到他们需要使用按位运算而不是逻辑比较(例如&lt;=)。它还被标记为c 和c++,所以我对限制进行了硬编码,而不是依赖std 命名空间。
  • 否定的number你可以试试if (std::numeric_limits&lt;int8_t&gt;::min() == (number &amp; std::numeric_limits&lt;int8_t&gt;::min()))
  • 我相信作者是用C写的(但有点不清楚)。我更新了代码以使用 &lt;stdint.h&gt; 而不是硬编码值。
【解决方案4】:

如果数字是正数,您可以屏蔽掉底部的 8 或 16 位并进行比较。
如果数字是负数,你有:

  • 对于介于 -1 和 -128 之间的数字(适合 8 位),前 25 位均已设置。
  • 从 -129 及以下,前 25 位至少有一个零。
  • 对于介于 -1 和 -32768 之间的数字(适合 16 位),最高 17 位均已设置。
  • 从 -32769 及以下,前 17 位至少有一个零。

所以,也许是这样的:

char* answer[] = { "no", "yes" };
if (!(number >> 31))
{
    printf("Fits in eight: %s\n", answer[number == (number & 0xff)]);
    printf("Fits in 16: %s\n", answer[number == (number & 0xffff)]);
}
else
{
    printf("Fits in eight: %s\n", answer[(number >> 7) == 0x1ffffff]);
    printf("Fits in 16: %s\n", answer[(number >> 15) == 0x1ffff]);
}

【讨论】:

    猜你喜欢
    • 2015-09-22
    • 1970-01-01
    • 2015-05-25
    • 2013-01-09
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-06
    相关资源
    最近更新 更多