php网站挂到linux服务器上应该这么做/地推拉新app推广平台
这个网站:https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html说它是为无符号整数定义的。 在某些情况下,将其用于带符号的int会导致错误的结果吗?
也许。 如果说它仅是为未签名定义的,则签名可能有效。 不要依靠它。
为什么在调用它之前不只是将其转换为unsigned int(该操作完全由语言定义)? 您是否打算传递负数,如果是,您想要什么答案?
__builtin_popcount是gcc特定的扩展名。它的作用类似于声明:
int __builtin_popcount (unsigned int x);
如果您有一个带有该声明的实际函数,并且该声明可见,那么您可以向其传递任何数字类型的参数。由于声明是原型,因此您传递的所有参数都将隐式转换为参数类型unsigned int。
从(有符号)int到unsigned int的转换定义良好。如果要转换的值在0 .. INT_MAX范围内,则该值保持不变。否则,它将包装模块UINT_MAX+1。例如,将-1转换为unsigned int会产生UINT_MAX,如果unsigned int为32位宽,则它为232-1。
所以问题是,gcc是否将__builtin_popcount视为具有可见原型的函数?由于它是语言扩展,因此不需要,而且gcc手册也不是很清楚。它显示了它的原型,但这并不一定意味着该原型对您的代码可见。
使用gcc 4.8.2进行的实验表明,它被视为具有可见原型的函数。 (您不能像使用普通函数那样将其地址存储在指针中,但这不成问题)。该程序:
#include
#include
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, __builtin_popcount(n));
printf("popcount(%g) = %d\", x, __builtin_popcount(x));
printf("popcount(%u) = %d\", x_rep, __builtin_popcount(x_rep));
return 0;
}
在我的系统上产生以下输出:
popcount(21845) = 8
popcount(21845) = 8
popcount(1185589760) = 11
这意味着x的值将转换为unsigned int,而不仅仅是重新解释。当我们明确地重新解释其表示形式时,我们会得到不同的结果。
因此,除非gcc出于某种原因(似乎不太可能)更改了内置函数的实现,否则将带符号的int传递给__builtin_popcount应该会按预期工作,将int的值转换为unsigned int。并假设有符号整数为2的补码表示法(这是一个相当安全的假设),从int转换为unsigned int不会更改表示,因此__builtin_popcount将为您正确设置设置的位数在int的表示形式中,包括符号位。
当然,如果您不想依赖于此,则始终可以使用强制转换将值显式转换为unsigned int。强制转换通常容易出错,通常最好使用隐式转换,但在这种情况下,这可能是一种合理的方法。
综上所述,如果您要计算一个值的总体计数,那么从无符号值开始几乎肯定更有意义。您传递给__builtin_popcount的带符号int值很可能首先应该定义为unsigned int。
最后,您写道__builtin_popcount是"为无符号整数定义的"。实际上,它仅针对类型unsigned int定义,通常不针对无符号整数定义。内置三种不同的功能:
int __builtin_popcount (unsigned int x);
int __builtin_popcountl (unsigned long x);
int __builtin_popcountll (unsigned long long x);
您需要使用正确的数据类型。在unsigned long long对象上使用__builtin_popcount可能会忽略该值的上半部分,可能没有编译器的警告。
为了补充其他答案,这是一个自己动手做的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);
}
因此,您可以看到,当对有符号整数调用__builtin_popcount时,gcc将其强制转换为记录的参数类型unsigned int。
是。您也可以传递signed int并假设负数表示为2的补数(这在现代系统中最多)。
如果数字为正,则与unsigned int一样好。但是,如果传递负数,例如-1,它将转换为很大的unsigned int类型,但不会更改位模式,因此不会更改位数。 signed或unsigned与位模式无关,在计算值时必须与位模式进行解释。
signed int i = -1; //i has N number of 1 bit
unsigned int j = -1; //j has N number of 1 bit as well.
//j becomes a very large number!
希望能有所帮助。
我不认为那通常是有效的,例如。 第4.7节([conv.integral])。 并且它甚至不能保证__builtin_something的行为类似于带有无符号参数的普通函数。
@deviantfan:我添加了"假设负数表示为2s表示恭维(在系统上最多)。"
假设编译器为__builtin_popcount提供了等效的可见原型。 事实证明确实如此,但是从文档中看不出来是100%清楚的。