C++ 我可以使用有符号整数作为uu builtin_popcount()的参数吗?
此站点:表示它是为无符号整数定义的。在某些情况下,将其用于带符号int是否会产生错误的结果 是的。您也可以传递有符号整数,假设负数表示为2的补码(这在现代系统中最常见) 如果数字为正数,则等于C++ 我可以使用有符号整数作为uu builtin_popcount()的参数吗?,c++,gcc,g++,gnu,C++,Gcc,G++,Gnu,此站点:表示它是为无符号整数定义的。在某些情况下,将其用于带符号int是否会产生错误的结果 是的。您也可以传递有符号整数,假设负数表示为2的补码(这在现代系统中最常见) 如果数字为正数,则等于无符号int。但是,如果传递一个负数,例如-1,它将转换为非常大的类型无符号int,,但它不会改变位模式-因此位的数量signed或unsigned与位模式无关,它必须与位模式相关 希望对您有所帮助。\uu内置的popcount是一个特定于gcc的扩展。它的作用类似于具有以下声明的函数: int __bui
无符号int
。但是,如果传递一个负数,例如-1
,它将转换为非常大的类型无符号int
,,但它不会改变位模式-因此位的数量signed
或unsigned
与位模式无关,它必须与位模式相关
希望对您有所帮助。
\uu内置的popcount
是一个特定于gcc的扩展。它的作用类似于具有以下声明的函数:
int __builtin_popcount (unsigned int x);
如果您有一个带有该声明的实际函数,并且它的声明是可见的,那么您可以向它传递任何数值类型的参数。由于该声明是一个原型,您传递的任何参数都将隐式转换为参数类型,unsigned int
从(有符号)int
到无符号int
的转换定义良好。如果要转换的值在范围0
内INT_MAX
,值不变。否则,它将被包装为模块UINT\u MAX+1
。例如,将-1
转换为unsigned int
会产生UINT\u MAX
,如果unsigned int
为32位宽,则为232-1
所以问题是,gcc是否将\uuuu内置\uuPopCount
视为具有可见原型的函数?因为它是一种语言扩展,所以不必这样做,而且gcc手册也不完全清楚。它显示了它的原型,但这并不一定意味着原型对代码是可见的
GCC4.8.2的实验表明,它被视为具有可见原型的函数。(不能像对普通函数那样将其地址存储在指针中,但这不应该是问题)。该计划:
#include <stdio.h>
#include <string.h>
int main(void) {
unsigned int n = 21845; // 0x5555, popcount = 8
float x = 21845.0;
unsigned int x_rep;
memcpy(&x_rep, &x, sizeof x_rep);
if (sizeof x != sizeof x_rep) {
puts("WARNING: Sizes do not match");
}
printf("popcount(%u) = %d\n", n, __builtin_popcount(n));
printf("popcount(%g) = %d\n", x, __builtin_popcount(x));
printf("popcount(%u) = %d\n", x_rep, __builtin_popcount(x_rep));
return 0;
}
这意味着x
的值将转换为无符号int
,而不仅仅是重新解释。当我们明确地重新解释它的表示时,我们会得到不同的结果
因此,除非gcc出于某种原因(似乎不太可能)更改其内置函数的实现,否则将有符号的int
传递给\uuuBuiltin\uPopCount
应该按预期工作,将int
值转换为无符号的int
。并且假设有符号整数采用2的补码表示法(这是一个相当安全的假设),从int
转换为unsigned int
不会改变表示法,因此\u builtin\u popcount
将为您提供在int
表示法中设置的位的正确计数,包括符号位
当然,如果您不想依赖于此,则始终可以使用强制转换将值显式转换为unsigned int
。强制转换通常容易出错,通常最好使用隐式转换,但在这种情况下,这可能是一种合理的方法
话虽如此,如果要计算一个值的总体计数,几乎可以肯定的是,从一个无符号值开始更合理。您传递给\u builtin\u popcount
的有符号int
值很可能应该首先定义为无符号int
最后,您编写了\uuuu内置\uPopCount
是“为无符号整数定义的”。实际上,它只为类型无符号int
定义,一般不为无符号整数定义。有三种不同的内置功能:
int __builtin_popcount (unsigned int x);
int __builtin_popcountl (unsigned long x);
int __builtin_popcountll (unsigned long long x);
您需要为正在处理的数据类型使用正确的方法。在
无符号long-long
对象上使用\uuuu内置\uPopCount
可能会忽略该值的上半部分,可能不会收到编译器的警告。为了补充其他答案,下面是一个自己动手,gcc正在做什么的示例。让我们编写一个简单的测试用例:
int f(int i){
return __builtin_popcount(i);
}
并使用gcc-c test.c-fdump tree all
编译它。这将创建多个文件,从test.c.003t.original
开始:
;; Function f (null)
;; enabled by -tree-original
{
return __builtin_popcount ((unsigned int) i);
}
因此,您可以看到,当对有符号整数调用
\u builtin\u popcount
时,gcc可能会将其转换为有文档记录的参数类型unsigned int
。如果它说它只为unsigned定义,signed可能有效,也可能无效。不要依赖它。为什么不在调用它之前直接转换为unsigned int
(一种完全由语言定义的操作)?你打算传递负数吗?如果是的话,你想要什么答案?我认为这通常是无效的,例如第4.7节([conv.integral])。而且它甚至不能保证“内置”某些东西的行为与带有无符号参数的正常函数相似。@DeviceFan:我添加了“假设负数表示为2的恭维(这在系统上是最常见的)。”这假设编译器为\u内置\u popcount
提供了一个可视原型。事实证明确实如此,但文档中并没有100%明确说明这一点。
int f(int i){
return __builtin_popcount(i);
}
;; Function f (null)
;; enabled by -tree-original
{
return __builtin_popcount ((unsigned int) i);
}