简体   繁体   English

我可以使用有符号整数作为__builtin_popcount()的参数吗?

[英]Can I use a signed integer as an argument to __builtin_popcount()?

This site: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html says that it is defined for unsigned integers. 该站点: https//gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html表示它是为无符号整数定义的。 Will using it for signed int give wrong results in some cases or not? 将它用于signed int会在某些情况下给出错误的结果吗?

__builtin_popcount is a gcc-specific extension. __builtin_popcount是特定于gcc的扩展。 It acts like a function with the declaration: 它的作用类似于声明的函数:

int __builtin_popcount (unsigned int x);

If you had an actual function with that declaration, and its declaration were visible, then you could pass an argument of any numeric type to it. 如果你有一个具有该声明的实际函数, 并且它的声明是可见的,那么你可以将任何数字类型的参数传递给它。 Since the declaration is a prototype, any argument you pass would be implicitly converted to the parameter type, unsigned int . 由于声明是原型,因此您传递的任何参数都将隐式转换为参数类型unsigned int

Conversion from (signed) int to unsigned int is well defined. 从(signed) intunsigned int是明确定义的。 If the value being converted is within the range 0 .. INT_MAX , the value is unchanged. 如果转换的值在0 .. INT_MAX范围内,则该值不变。 Otherwise, it's wrapped module UINT_MAX+1 . 否则,它的包装模块UINT_MAX+1 For example, converting -1 to unsigned int yields UINT_MAX , which is 2 32 -1 if unsigned int is 32 bits wide. 例如,将-1转换为unsigned int产生UINT_MAX ,如果unsigned int为32位宽,则为2 32 -1。

So the question is, does gcc treat __builtin_popcount as a function with a visible prototype? 所以问题是,gcc是否将__builtin_popcount视为具有可见原型的函数? Since it's a language extension, it doesn't have to, and the gcc manual isn't entirely clear. 因为它是语言扩展,所以它没有必要 ,并且gcc手册并不完全清楚。 It shows a prototype for it, but that doesn't necessarily mean that prototype is visible to your code. 它显示了它的原型,但这并不一定意味着您的代码可以看到原型。

An experiment with gcc 4.8.2 indicates that it is treated as a function with a visible prototype. 使用gcc 4.8.2的实验表明它被视为具有可见原型的函数。 (You can't store its address in a pointer as you could for an ordinary function, but that shouldn't be a problem). (您不能像普通函数那样将其地址存储在指针中,但这不应该是一个问题)。 This program: 这个程序:

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

produces this output on my system: 在我的系统上生成此输出:

popcount(21845) = 8
popcount(21845) = 8
popcount(1185589760) = 11

Which means that the value of x is converted to unsigned int , not just reinterpreted. 这意味着x的值被转换为unsigned int ,而不仅仅是重新解释。 When we explicitly reinterpret its representation, we get different results. 当我们明确地重新解释它的表示时,我们会得到不同的结果。

So unless gcc changes its implementation of builtin functions for some reason (that seems unlikely), passing a signed int to __builtin_popcount should work as expected, converting the int value to unsigned int . 因此,除非gcc由于某种原因(似乎不太可能)更改其内置函数的实现,否则将signed int传递给__builtin_popcount应该按预期工作,将int值转换为unsigned int And assuming a 2's-complement representation for signed integers (which is a reasonably safe assumption), converting from int to unsigned int does not change the representation, so __builtin_popcount will give you a correct count of the bits that are set in the representation of the int , including the sign bit. 并假设有符号整数的二进制补码表示(这是一个相当安全的假设),从int转换为unsigned int不会改变表示,因此__builtin_popcount将为您提供在表示中设置的位的正确计数。 int ,包括符号位。

Of course if you don't want to depend on this, you can always explicitly convert the value to unsigned int using a cast. 当然,如果您不想依赖于此,则始终可以使用强制转换将值显式转换为unsigned int Casts are often error-prone, and it's usually better to use implicit conversions, but in this case it might be a reasonable approach. 转换通常容易出错,使用隐式转换通常更好,但在这种情况下,它可能是一种合理的方法。

Having said all this, if you're computing the population count of a value, it almost certainly makes more sense to start with an unsigned value. 说完这一切之后,如果你计算一个值的总体数,那么从无符号值开始几乎肯定更有意义。 It's likely that the signed int value you're passing to __builtin_popcount should have been defined as an unsigned int in the first place. 这很可能是签署int你传递价值__builtin_popcount 应该被定义为unsigned int放在首位。

Finally, you wrote that __builtin_popcount is "defined for unsigned integers". 最后,您写道__builtin_popcount是“为无符号整数定义的”。 Actually, it's defined only for type unsigned int , not for unsigned integers in general. 实际上,它只定义为unsigned int类型,而不是一般的无符号整数。 There are three different builtin functions: 有三种不同的内置函数:

int __builtin_popcount (unsigned int x);
int __builtin_popcountl (unsigned long x);
int __builtin_popcountll (unsigned long long x);

You need to use the right one for the type of data you're working with. 您需要使用正确的数据来处理您正在使用的数据类型。 Using __builtin_popcount on an unsigned long long object will likely ignore the upper half of the value, probably without a warning from the compiler. unsigned long long对象上使用__builtin_popcount可能会忽略值的上半部分,可能没有来自编译器的警告。

To complement the other answers, here is a do-it-yourself, what-is-gcc-doing example. 为了补充其他答案,这里是一个自己动手,做什么的gcc做的例子。 Let us write a simple testcase: 让我们编写一个简单的测试用例:

int f(int i){
  return __builtin_popcount(i);
}

and compile it with gcc -c test.c -fdump-tree-all . 并使用gcc -c test.c -fdump-tree-all编译它。 This creates several files, starting with test.c.003t.original : 这将创建几个文件,从test.c.003t.original开始:

;; Function f (null)
;; enabled by -tree-original

{
  return __builtin_popcount ((unsigned int) i);
}

So you can see that when __builtin_popcount is called on a signed integer, gcc casts it to the documented argument type of unsigned int . 因此,您可以看到,当在有符号整数上调用__builtin_popcount时,gcc会将其转换为unsigned int的文档参数类型。

Yes. 是。 You can pass signed int as well — assuming negative number is represented as 2's complement (which is most on the modern systems) . 您也可以传递signed int - 假设负数表示为2的补码(在现代系统中最多)

If the number is positive, then it is as good as unsigned int . 如果数字是正数,则它与unsigned int一样好。 If you pass a negative number however, say -1 , it will convert into a very large number of type unsigned int , but it will not change the bits-pattern — hence the number of bits . 但是如果传递一个负数,比如-1 ,它将转换为非常大量的unsigned int类型, 但它不会改变位模式 - 因此也就是位数 signed or unsigned has nothing to do with bit-patterns, it has to do the interpretation of bits-pattern when computing value . signedunsigned与位模式无关,它必须在计算值时对位模式进行解释

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!

Hope that helps. 希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 gcc的“ __builtin_popcount”如何工作? - How does “__builtin_popcount” of gcc work? 标准::位集<N> ::count 与 __builtin_popcount - std::bitset<N>::count vs __builtin_popcount 为什么 __builtin_popcount 比我自己的位计数 function 慢? - Why is __builtin_popcount slower than my own bit counting function? 我该如何修复它“有符号和无符号 integer 表达式之间的比较 [-Werror=sign-compare]” - How can I fix it "comparison between signed and unsigned integer expressions [-Werror=sign-compare]" 我可以有条件地使用超过1个参数吗? - Can I Conditionally Use More Than 1 Argument? 我可以在if语句中使用“ x = 2”作为参数吗? - can I use “x=2” as an argument inside an if statement? 为什么此用于处理时间戳的代码使用带符号整数? - Why does this code for dealing with timestamps use signed integer? 为什么 Qt 为其容器类使用有符号整数类型? - Why does Qt use a signed integer type for its container classes? 如何在不调用未定义或实现定义的行为的情况下从 uint8_t 缓冲区读取有符号整数? - How can I read a signed integer from a buffer of uint8_t without invoking un- or implementation-defined behaviour? __builtin_bswap16 是否可用于签名短片? - availability of __builtin_bswap16 for signed short?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM