我想知道是否有一种有效的方法可以将有符号整数转换为无符号短整数,其中负整数值在无符号短整数(在 C ANSI 中)中被简单地设置为 0。我知道这可以通过如下简单的 if 语句来完成:
int val1;
unsigned short val2;
val1=-5;
if(val1<0){
val2=0;
}else{
val2=(unsigned short) val1;
}
这种转换在我的程序中经常发生,并且
val1
为负的情况非常罕见,所以每次都出现这种 if 语句似乎有点过分了。
有没有更有效的方法来进行这种转换?
经常有效的一件事是直接在表达式中使用布尔结果(
0
或 1
)。
而不是你的
if
/else
构建try
val2 = val1 * (val1 > 0);
如果您追求绝对最佳性能,请不要忘记使用不同的编译器选项测量不同的代码。
如果您在 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;
}
这里有几种不同的方法:
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
语句更有效。