使用size_t长度会影响编译器优化吗? [英] Using `size_t` for lengths impacts on compiler optimizations?

查看:80
本文介绍了使用size_t长度会影响编译器优化吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读这个问题时,我已经看到第一个评论说:

While reading this question, I've seen the first comment saying that:


size_t 并不是一个好主意,出于优化/ UB的原因,适当的类型是带符号的类型。

size_t for length is not a great idea, the proper types are signed ones for optimization/UB reasons.

后面是另一条支持推理的评论。是真的吗

followed by another comment supporting the reasoning. Is it true?

这个问题很重要,因为如果我要写例如矩阵库,图像尺寸可以为 size_t ,只是为了避免检查它们是否为负数。但是,所有循环自然会使用 size_t 。这可能会对优化产生影响吗?

The question is important, because if I were to write e.g. a matrix library, the image dimensions could be size_t, just to avoid checking if they are negative. But then all loops would naturally use size_t. Could this impact on optimization?

推荐答案

size_t 大多数情况下是历史性事故-如果您的世界是16位,则最大对象大小从32767变为65535是一个大胜利;在当今的主流计算(以64位和32位为标准)中, size_t 是未签名的事实在很大程度上是令人讨厌的。

size_t being unsigned is mostly an historical accident - if your world is 16 bit, going from 32767 to 65535 maximum object size is a big win; in current-day mainstream computing (where 64 and 32 bit are the norm) the fact that size_t is unsigned is mostly a nuisance.

尽管无符号类型具有 less 不确定的行为(因为保证了环绕),但实际上它们大多具有位域语义,这通常是导致错误和其他不良后果的原因。特别是:

Although unsigned types have less undefined behavior (as wraparound is guaranteed), the fact that they have mostly "bitfield" semantics is often cause of bugs and other bad surprises; in particular:


  • 无符号值之间的差异也是无符号的,并且具有通常的环绕语义,因此,如果您期望负数

  • difference between unsigned values is unsigned as well, with the usual wraparound semantics, so if you may expect a negative value you have to cast beforehand;

unsigned a = 10, b = 20;
// prints UINT_MAX-10, i.e. 4294967286 if unsigned is 32 bit
std::cout << a-b << "\n"; 


  • 通常,在有符号/无符号比较和数学运算中,无符号获胜(因此,值会隐式地转换为无符号数),这又会导致意外;

  • more in general, in signed/unsigned comparisons and mathematical operations unsigned wins (so the signed value is casted to unsigned implicitly) which, again, leads to surprises;

    unsigned a = 10;
    int b = -2;
    if(a < b) std::cout<<"a < b\n"; // prints "a < b"
    


  • 无符号语义通常会出现问题,因为您希望索引在边界条件下变为负数

  • in common situations (e.g. iterating backwards) the unsigned semantics are often problematic, as you'd like the index to go negative for the boundary condition

    // This works fine if T is signed, loops forever if T is unsigned
    for(T idx = c.size() - 1; idx >= 0; idx--) {
        // ...
    }
    


  • 此外,价值不能假设负值主要是稻草人; 可以避免检查负值,但是由于隐式的有符号-无符号转换,它不会停止任何错误-您只是在怪罪。如果用户使用 size_t 将负值传递给您的库函数,则它将变成一个很大的数字,如果不是更糟的话,这也是错误的。

    Also, the fact that an unsigned value cannot assume a negative value is mostly a strawman; you may avoid checking for negative values, but due to implicit signed-unsigned conversions it won't stop any error - you are just shifting the blame. If the user passes a negative value to your library function taking a size_t, it will just become a very big number, which will be just as wrong if not worse.

    int sum_arr(int *arr, unsigned len) {
        int ret = 0;
        for(unsigned i = 0; i < len; ++i) {
            ret += arr[i];
        }
        return ret;
    }
    
    // compiles successfully and overflows the array; it len was signed,
    // it would just return 0
    sum_arr(some_array, -10);
    

    对于优化部分:带符号类型在这方面的优势被高估了;是的,编译器可以假设永远不会发生溢出,因此在某些情况下它可以变得更聪明,但是通常这不会改变游戏规则(因为通常,环绕式语义在当今的体系结构中免费提供);最重要的是,像往常一样,如果您的探查器发现某个特定区域是瓶颈,则可以对其进行修改以使其运行更快(如果发现有利的话,可以在本地进行切换类型以使编译器生成更好的代码)。

    For the optimization part: the advantages of signed types in this regard are overrated; yes, the compiler can assume that overflow will never happen, so it can be extra smart in some situations, but generally this won't be game-changing (as in general wraparound semantics comes "for free" on current day architectures); most importantly, as usual if your profiler finds that a particular zone is a bottleneck you can modify just it to make it go faster (including switching types locally to make the compiler generate better code, if you find it advantageous).

    长话短说:我会选择签名而不是出于性能方面的考虑,而是因为在大多数常见情况下语义通常都不那么令人惊讶/敌对。

    Long story short: I'd go for signed, not for performance reasons, but because the semantics is generally way less surprising/hostile in most common scenarios.

    这篇关于使用size_t长度会影响编译器优化吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆