【问题标题】:Converting signed int to unsigned short with negative values being set to zero in C将有符号的 int 转换为无符号的 short,在 C 中将负值设置为零
【发布时间】:2014-06-26 23:00:00
【问题描述】:

我想知道是否有一种有效的方法将有符号整数转换为无符号短整数,其中负整数值在无符号短整数中简单地设置为 0(在 C ANSI 中)。我知道这可以通过一个简单的 if 语句来完成,如下所示:

int val1;
unsigned short val2;

val1=-5; 
if(val1<0){
   val2=0;
}else{
   val2=(unsigned short) val1;
}

这种转换在我的程序中经常发生,val1 是否定的情况非常罕见,所以每次都出现这个 if 语句似乎有点过头了。

有没有更有效的方法来进行这种转换?

【问题讨论】:

  • 如果这是一个不常见的情况,分支预测器可能已经足够好了(显然取决于你的架构)。
  • 我建议你在if中写出出现次数较多的条件,然后使用else作为出现次数较少的条件。
  • 也可以试试val2 = val1 * (val1 &gt; 0); 并进行测量。
  • 您可以创建一个inline 函数(如inline si2us(int si, unsigned short *us))来处理转换。请注意,inline 来自 C99,可能无法由 Microsoft Visual Studio C 编译器实现。
  • @JoachimPileborg 我认为它在 MSVC 的 C 编译器中称为 __inline。但无论如何,它不是 ANSI C。

标签: c int type-conversion ansi unsigned-integer


【解决方案1】:

如果您在 gcc 下,可以使用内置函数为优化器提供有关整数(或布尔)表达式可能结果的线索。

#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

在以下示例中,我们将分支标记为可能为真:

const char *home_dir ;

home_dir = getenv("HOME");
if (likely(home_dir))
    printf("home directory: %s\n", home_dir);
else
    perror("getenv");

适应您的代码:

#include <stdio.h>

#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

int main(void)
{
    int val1;
    unsigned short val2;

    val1 = -5; 
    if (unlikely(val1 < 0)) {
        val2 = 0;
    } else {
        val2 = (unsigned short)val1;
    }
    return 0;
}

另一种使用指定宽度和位运算符的方式:

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

int main(void)
{
    int32_t val1;
    uint16_t val2;

    val1 = -5; 
    val2 = (0xffff ^ (val1 >> 31)) & val1;
    printf("%u\n", val2);
    return 0;
}

【讨论】:

  • 我没有使用 gcc,但是我会看看我的编译器是否有类似于 __builtin_expect 的东西。我正在为嵌入式系统使用 IAR 编译器。
【解决方案2】:

通常有效的一件事是直接在表达式中使用布尔结果(01)。

而不是您的if/else 构造尝试

val2 = val1 * (val1 > 0);

如果您追求绝对最佳性能,请不要忘记使用不同的编译器选项测量不同的代码。

【讨论】:

  • 乘法不会比条件语句花费更长的时间吗?还是这取决于编译器?
  • 这是01 的简单乘法。该语句没有分支。它可能比if 更好用;它可能不会。 你需要衡量。重点是:方法值得一试。
  • 感谢您的提示。我打算运行这个嵌入式,所以这可能会改变,但在 Visual Studio 中运行 200 万次并没有显示出我的 CPU 计算时间的显着差异。但正如我所说,当我嵌入它时,这可能会改变,所以我会记住它。谢谢。
【解决方案3】:

这里有几种不同的方法:

val2 = (unsigned short)val1 * (1+(val1>>(sizeof(val1)*8-1)));
val2 = (unsigned short)val1 * (1^((val1>>(sizeof(val1)*8-1))&1));
val2 = (unsigned short)val1 * (1^((unsigned)val1>>(sizeof(val1)*8-1)));
val2 = (unsigned short)val1 * (1-((unsigned)val1>>(sizeof(val1)*8-1)));

您可以通过将8 替换为CHAR_BIT(在limits.h 中定义)来使其更通用。

请注意,它不一定比简单的if/else 语句更有效。

【讨论】:

    猜你喜欢
    • 2015-04-29
    • 1970-01-01
    • 2012-05-20
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多