在C中将有符号int转换为无符号short,并将负值设置为零

jyztefdp  于 2023-03-28  发布在  其他
关注(0)|答案(3)|浏览(149)

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

int val1;
unsigned short val2;

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

这种转换在我的程序中经常发生,而val1为负的情况非常罕见,所以每次都出现这个if语句似乎有点矫枉过正。
有没有更有效的方法来进行这种转换?

qq24tv8q

qq24tv8q1#

一种常用的方法是直接在表达式中使用布尔结果(01)。
而不是您的if/else构造尝试

val2 = val1 * (val1 > 0);

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

voase2hg

voase2hg2#

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

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

在下面的例子中,我们将分支标记为likely true:

const char *home_dir ;

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

Adatped到您的代码:

#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;
}
smtd7mpg

smtd7mpg3#

以下是几种不同的方法:

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语句更有效。

相关问题