【问题标题】:Can I increase int i by more than one using the i++ syntax?我可以使用 i++ 语法将 int i 增加一个以上吗?
【发布时间】:2010-07-14 14:05:13
【问题描述】:

int fkt(int &i) { 返回我++; }

int main()
{
  int i = 5;
  printf("%d ", fkt(i));
  printf("%d ", fkt(i));
  printf("%d ", fkt(i));
}

打印“5 6 7”。假设我想像这样打印“5 7 9”,是否可以在 fkt() 中没有临时变量的情况下以类似的方式进行操作? (临时变量会略微降低效率,对吗?)即,类似于

return i+=2 

return i, i+=2; 

这两个都是先增加i再返回,这不是我需要的。

谢谢

编辑:主要原因,我在一个函数中而不是在外面是因为 fkt 将是一个函数指针。原始函数将对 i 执行其他操作。我只是觉得使用 {int temp = i;我+=2; return temp;} 似乎不如 {return i++;} 好。

printf我不关心,这只是为了说明结果的使用。

EDIT2:哇,这似乎更像是一个聊天而不是传统的板:) 感谢所有的答案。我的fkt其实就是这个。根据某些条件,我会将 get_it 定义为 get_it_1、get_it_2 或 get_it_4:

unsigned int (*get_it)(char*&);

unsigned int get_it_1(char* &s)
  {return *((unsigned char*) s++);}
unsigned int get_it_2(char* &s)
  {unsigned int tmp = *((unsigned short int*) s); s += 2; return tmp;}
unsigned int get_it_4(char* &s)
  {unsigned int tmp = *((unsigned int*) s); s += 4; return tmp;}

对于get_it_1来说,就是这么简单……以后我会尽量提供更多背景知识……

【问题讨论】:

  • 忽略那些效率考虑并使用有效的解决方案。
  • 我只是想确保您意识到 printf 比 i+=2 慢数千倍。
  • SadSido 是对的...i+=2;返回我;会是一样的。如果你仔细想想,i++ 实际上只是一种方便的表示 i+=1 的方式,这是一种方便的表示 i=i+1 的方式。 (有趣的是,我们程序员如何想出方便的方法来使我们的方便方法更方便)您不会有任何开销,因为汇编指令已经有一个“立即添加”选项用于与整数相加。无需额外注册!
  • 先写出最容易阅读和维护的代码,然后测量。如果您通过测量发现性能问题,首先找到对性能影响最大的区域,然后在那里实施您认为可以改进的地方,然后再次测量,看看您的猜测是正确的。
  • “我们应该忘记小的效率,比如说大约 97% 的时间:过早的优化是万恶之源。然而,我们不应该放弃关键的 3% 的机会。一个好的程序员不会因为这样的推理而自满,他会明智地仔细查看关键代码;但只有在识别出该代码之后”——Donald Kunth——en.wikipedia.org/wiki/Program_optimization

标签: c++ c


【解决方案1】:

“临时变量会略微降低效率,对吗?”

错了。

你测量了吗?请注意++ 仅在 PDP-11 上具有神奇的效率能力。在大多数其他处理器上,它与+=1 相同。请测量两者以了解实际差异。

【讨论】:

  • 在 PDP-11 上,编译器优化由人工执行;)
  • 好吧,我很感兴趣 - PDP-11 有什么魔力意味着 i++ 比 i+=1 更快?某种片上增量指令类似于 6502 上的 INX/INY,编译器知道并优先使用标准 ALU 加法?
  • PDP11 的体系结构(以及此后出现的许多体系结构)可以在一条指令中取消引用和递增或递减指针。通常,增量/减量被强制为加载/存储的数据大小(例如,如果加载/存储一个字节,则为 1,如果是 16 位字,则为 2,等等)不同的处理器支持前增量和后增量的不同组合/递减。我知道除了指针解引用之外,没有任何架构直接支持后增量,尽管在某些情况下,一些高度流水线的处理器可能会受益于后增量。
  • @Matt Joiner:不是编译器,只是优化器。使用 pre-increment 和 post-increment ++ 纯粹是对 I/O 驱动程序和内核数据结构更新等的性能优化调整。如果他们太慢了。
  • 在旧的 Z80 芯片上,add 比 inc 慢 :)
【解决方案2】:

(临时变量会略微降低效率,对吧?)

如果这是你问的主要原因,那么你担心得太早了。在出现实际性能问题之前,不要对编译器进行事后猜测。

如果你希望 fkt 能够给 i 添加不同的数量,那么你需要传递一个参数。没有实质性的理由更喜欢++ 而不是+=

【讨论】:

  • +1:“不要猜测你的编译器”。一个很好的人生座右铭。
【解决方案3】:

你可以递增两次,然后减去,类似于:

return (i += 2) - 2

不过,只是回答这个问题,我认为您不应该害怕使用临时变量。

【讨论】:

  • 实际问题的最佳答案。我同意你和其他答案,即临时会更好。
  • 就效率而言,使用 gcc 4.4.1 -O2 编译产生的程序集与使用临时程序完全相同。
【解决方案4】:

如果您确实需要这种速度,请检查编译器输出的汇编代码。如果你这样做:

int t = i;
i+=2;
return t;

然后编译器可能会优化它,同时将函数内联成如下内容:

printf("%d ", i);
i+=2;

这将是最好的。

编辑:现在你说你通过函数指针跳转到这个函数?与使用临时变量相比,通过指针调用函数非常慢。我不确定,但我想我记得英特尔文档说它在 Core 2s 和 i7s 上大约有 20-30 个 cpu 周期,也就是说,如果你的函数代码都在缓存中。由于编译器在被指针调用时不能内联你的函数,所以 ++ 也会创建一个临时变量。

【讨论】:

    【解决方案5】:

    临时变量会稍微 降低效率,对吧?

    始终考虑“过早的优化是万恶之源”。花时间在其他部分上,然后尝试优化它。 += 和 ++ 可能会导致相同的结果。你的电脑会管理 ;)

    【讨论】:

      【解决方案6】:

      嗯,你可以的

      return i+=2, i-2;
      

      也就是说,只要遵循这个简单的格言:

      编写易于理解的代码。

      易于人类理解的代码通常易于编译器理解,因此编译器可以对其进行优化。

      为了优化你的代码而编写疯狂的东西通常只会让编译器感到困惑,并使编译器更难优化你的代码。

      我会推荐

      int fkt(int &i)
      {
          int orig = i;
          i += 2;
          return orig;
      }
      

      【讨论】:

      • 这两者的汇编差异应该是微不足道的,第二个更好读。
      • +1 表示简单的格言,“编写易于理解的代码。”
      • 第二个示例仅适用于 C++(或至少 GCC 会抛出 error: expected ';', ',' or ')' before '&' token)。在标准 C 中是否有与此一样好的等效功能?
      【解决方案7】:

      “临时变量”不太可能降低性能,因为 i++ 必须在内部保持旧状态(即它隐式使用您所谓的临时变量)。但是,需要增加 2 的指令可能比用于 ++ 的指令慢。

      你可以试试:

      int fkt(int &i)
      {
        ++ii;
        return i++;
      }
      

      您可以将其与以下内容进行比较:

      int fkt(int &i)
      {
        int t = i;
        i += 2;
        return t;
      }
      

      也就是说,我认为您不应该过早地考虑任何此类性能问题。

      【讨论】:

        【解决方案8】:

        我认为你真正想要的是一个函子:

        class Fkt
        {
           int num;
        public:
           Fkt(int i) :num(i-2) {}
           operator()() { num+=2; return num; }
        }
        
        int main() 
        { 
          Fkt fkt(5); 
          printf("%d ", fkt()); 
          printf("%d ", fkt()); 
          printf("%d ", fkt()); 
        } 
        

        【讨论】:

          【解决方案9】:

          怎么样

          int a = 0;
          ++++a;
          

          不带临时变量的增量 +2。

          编辑: 糟糕,抱歉:没有注意到您想要达到 5、7、9。这需要临时变量,因此不能使用前缀表示法。

          【讨论】:

          • ++++a; 是非法的。您不能在序列点之间修改变量两次。
          • 这是否意味着我会得到一个编译错误?因为我没有。无论如何,我不明白为什么做 ++(++i) 是非法的。在再次增加变量之前增加变量对我来说似乎是完全合法的。但是你得到了经验,所以我想我还是错了。等待澄清:)
          • 好的,我想我明白了:我认为前缀增量定义了一个序列点,但似乎没有。那么,++a + ++b 也是非法的吗?当我读到 + 运算符也没有定义一个。
          • 对不起,我的意思是 ++a + ++a :) 显然前者不会改变同一个变量两次。
          • ++++a; 是非法的,即使没有考虑序列点; ++ 只适用于左值,++a 的结果不是左值。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-09
          • 1970-01-01
          • 2018-03-13
          • 2016-07-20
          • 2017-06-26
          • 2022-01-07
          相关资源
          最近更新 更多