【问题标题】:What does the unary plus operator do?一元加号运算符有什么作用?
【发布时间】:2010-10-18 04:05:39
【问题描述】:

一元加号运算符有什么作用?我找到了几个定义(herehere),但我仍然不知道它的用途。看起来它什么也没做,但这是有原因的,对吧?

【问题讨论】:

  • 我认为historical reason 被严重低估了。
  • 一个带有三种不同语言标签的问题是非常模棱两可/不好的!对于 C#(可重载)和 C(无重载)和 C++(可重载但从 C 继承它,因此也继承了它的属性)的答案非常不同。
  • 我想添加一个指向 Eric Lippert 的 C# 十大缺陷的链接。您会在荣誉奖中找到一元加号运算符:informit.com/articles/article.aspx?p=2425867 他基本上说应该删除它或者永远不要添加它。

标签: c# c++ c unary-operator


【解决方案1】:

实际上,一元加 确实 做某事 - 即使在 C 中也是如此。它对操作数执行 usual arithmetic conversions 并返回一个新值,该值可以是整数更大的宽度。如果原始值是宽度小于int 的无符号整数,则它也将更改为signed 值。

通常这不是那么重要,但它可以产生影响,所以使用一元加号作为一种“注释”表示不是一个好主意一个整数是正数。考虑以下 C++ 程序:

void foo(unsigned short x)
{
 std::cout << "x is an unsigned short" << std::endl;
}

void foo(int x)
{
 std::cout << "x is an int" << std::endl;
}

int main()
{
 unsigned short x = 5;
 foo(+x);
}

这将显示“x is an int”。

所以在这个例子中,一元加号创建了一个具有不同类型符号的新值。

【讨论】:

  • 如果你编写的代码在给定一个 short 和一个比较相等的 int 时产生给定结果,那么你可能有不同的问题
  • 谢谢,这很清楚(旁注:在 C 中,我无法让示例工作,因为我无法重载 foo 函数)
  • an integer of greater width是什么意思?
  • 在此上下文中,“宽度”是指与该值关联的存储字节数。
【解决方案2】:

如果你觉得有需要,它就会超载;对于所有预定义类型,它本质上是无操作的。

无操作一元算术运算符的实际用途非常有限,并且往往与在算术表达式中使用值的后果有关,而不是与运算符本身有关。例如,它可用于强制从较小的整数类型扩大到int,或确保表达式的结果被视为右值,因此与非const 引用参数不兼容。然而,我认为这些用途比可读性更适合编码高尔夫。 :-)

【讨论】:

  • 这实际上不是真的,如下面的几个例子所示。
  • 好吧,我相信它有一些用途,但下面讨论的大多数用途都与它是使用无操作运算符构建的数字表达式有关:例如,提升为 @ 987654323@ 并产生右值是表达式的影响,而不是 + 运算符本身的影响。
【解决方案3】:

来自 K&R 第二版:

一元 + 是新的 ANSI 标准。添加它是为了与一元对称 -。

【讨论】:

  • 当然。 *这是历史原因。 C++不得不适应它,所以它不得不处理重载。
【解决方案4】:

我看到它是为了清晰起见,强调正值与负值不同:

shift(+1);
shift(-1);

但这是一个很弱的用途。答案肯定是超载。

【讨论】:

  • 我也这样做过,尤其是在处理像vec3(+1,-1,-1)这样的向量时
【解决方案5】:

内置一元+ 所做的一件事是将左值转换为右值。例如,您可以这样做

int x;
&x;

但你不能这样做

&+x;

:)

附: “重载”绝对不是正确的答案。一元 + 继承自 C,C 中没有用户级运算符重载。

【讨论】:

    【解决方案6】:

    一元 + 完成的主要事情是将小于 int 数据类型的类型提升为 int。如果您尝试使用 std::cout 作为数字数据打印字符数据,这将非常有用。

    char x = 5;
    std::cout << +x << "\n";
    

    很不一样
    char x=5;
    std::cout << x << "\n";
    

    它也可用于重载,但实际上您的重载应该几乎是 NOP。

    【讨论】:

      【解决方案7】:

      如果您出于调试或任何原因需要打印原始字节的数值(例如,存储为 char 的小数),一元 + 可以简化打印代码。考虑

      char c = 42;
      cout << c << endl;           // prints "*\n", not what you want in this case
      cout << (int)c << endl;      // prints "42\n", ok
      cout << +c << endl;          // prints "42\n", much easier to type
      

      这只是一个简单的例子。我相信在其他时候,一元 + 可以帮助您将字节更像数字而不是文本。

      【讨论】:

        【解决方案8】:

        一个历史花絮。 C99 标准化委员会还认为一元加法的现有用途相当少见,他们考虑重用它以实现语言中的另一个特性就证明了这一点:抑制浮点常量表达式的翻译时求值。请参阅 C 基本原理,第 F.7.4 节中的以下引用:

        本规范的早期版本允许转换时间常数算术,但 授权一元 + 运算符,当应用于操作数时,抑制翻译时间 常量表达式的求值。

        最后,语义被颠倒了,在大多数情况下都强制执行运行时评估(至少达到“好像”规则),并且能够通过使用静态初始化器来强制执行翻译时评估。请注意,主要区别在于浮点异常的发生以及其他浮点舍入或精度设置(如果存在)。

        【讨论】:

          【解决方案9】:

          不多。允许operator+() 重载的一般论据是,在现实世界中肯定有重载operator-() 的用途,如果您允许重载@987654323,那将是非常奇怪(或不对称) @ 但不是operator+()

          我相信我首先从 Stroustrop 那里读到了这个论点,但我没有我的书来验证它。我可能错了。

          【讨论】:

            【解决方案10】:

            一元加号出现在 C 中,它完全没有做任何事情(很像 auto 关键字)。为了不拥有它,Stroustrup 将不得不引入与 C 的无缘无故的不兼容。

            一旦它出现在 C++ 中,就很自然地允许重载函数,就像一元减号一样,如果还没有,Stroustrup 可能会因此引入它。

            所以,这没有任何意义。它可以用作一种装饰,使事物看起来更对称,例如使用 +1.5 与 -1.5 相反。在 C++ 中,它可以被重载,但如果 operator+() 做任何事情,它会令人困惑。记住标准规则:重载算术运算符时,请执行 ints 之类的操作。

            如果您正在寻找它存在的原因,请查找有关 C 早期历史的一些信息。我怀疑没有充分的理由,因为 C 并不是真正设计的。考虑无用的 auto 关键字(可能与 static 形成对比,现在在 C++0x 中被回收)和 entry 关键字,它从来没有做任何事情(后来在 C90 中被省略了)。在一封著名的电子邮件中,Ritchie 或 Kernighan 说,当他们意识到运算符优先级存在问题时,已经有 3 个安装有数千行代码,他们不想破坏。

            【讨论】:

            • 我见过的唯一有意义的非算术重载是在正则表达式或语法中,其中 (+term) 表示一个或多个项目。 (这是相当标准的正则表达式语法)
            • 关于entry: (stackoverflow.com/q/254395/153285)。如今,如果您想要多个入口点,只需使用尾调用和配置文件引导优化。
            • 我相信即使在 C99 中,给定extern volatile int foo;,在任何可能存在任何方法来确定的平台上,给定语句+foo; 的编译器都需要执行指定地址的读取。读发生了。如果语句只是“foo”,我不确定是否需要这样做,尽管许多编译器会出于礼貌而这样做。
            【解决方案11】:

            我无法为此引用任何来源,但我已经明白它是用于显式类型提升,这意味着无损类型转换。这将其置于转换层次结构的顶部,

            • 促销: new_type operator+(old_type)
            • 转化: new_type(old_type)
            • 演员: operator(new_type)(old_type)
            • 强制: new_type operator=(old_type)

            当然,这是我对大约 15 年前阅读的一本微软(非常老的)c/c++ 手册中的注释的解释,所以请谨慎对待。

            【讨论】:

              【解决方案12】:
              #include <stdio.h>
              int main()
              {
                  unsigned short x = 5;
                  printf ("%d\n",sizeof(+x)); 
                  printf ("%d\n",sizeof(x)); 
                  return 0;
              }
              

              如上例所示,一元 + 确实改变了类型,大小分别为 4 和 2。奇怪的是表达式 +x 确实是在 sizeof 中计算的,我认为这不应该。也许是因为 sizeof 与一元 + 具有相同的优先级。

              【讨论】:

              • 作为记录,sizeof +x 确实实际评估表达式+x,它只是在编译时确定表达式的类型并返回它的大小类型。您可以通过编写sizeof ++x 在实践中看到这一点,这不会增加x 的值。
              【解决方案13】:

              我想您可以使用它来始终使数字为正数。只需将一元 + 运算符重载为 abs。真的不值得混淆你的开发者伙伴,除非你真的只是想混淆你的代码。然后它会很好地工作。

              【讨论】:

              • 这将使它与一元减号相反,这会令人困惑,除非您还将一元减号重载为负绝对值,这会使各种数学事物变得奇怪
              • 嗯,是的。这就是为什么我建议不要这样做。
              • @Davy8:是什么让你认为一元加号目前是一元减号的“对立面”?位补运算符~ 的“对立面”是什么?我不确定你对“相反”的定义是什么,但我怀疑它对一元加号和一元减号目前所做的经验有偏见。
              【解决方案14】:

              编辑完全重写了,因为我原来的答案很糟糕。

              这应该允许您将类型的显式声明处理为正值(我认为主要是在非数学运算中)。似乎否定会更有用,但我想这是一个可能会产生影响的例子:

              public struct Acceleration
              {
                  private readonly decimal rate;
                  private readonly Vector vector;
              
                  public Acceleration(decimal rate, Vector vector)
                  {
                      this.vector = vector;
                      this.rate = rate;
                  }
              
                  public static Acceleration operator +(Acceleration other)
                  {
                      if (other.Vector.Z >= 0)
                      {
                          return other;
                      }
                      return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
                  }
              
                  public static Acceleration operator -(Acceleration other)
                  {
                      if (other.Vector.Z <= 0)
                      {
                          return other;
                      }
                      return new Acceleration(other.Rate, new Vector(other.vector.X, other.Vector.Y, -other.vector.Z));
                  }
              
                  public decimal Rate
                  {
                      get { return rate; }
                  }
              
                  public Vector Vector
                  {
                      get { return vector; }
                  }
              }
              

              【讨论】:

              • 对我来说这看起来不像一元操作。它需要两个参数(四月和五月),所以它是二进制的。
              • 那是二进制加。一元加号只是“+1”之类的,没有左操作数。
              • 我的错。忘记了我的 CS101。固定。
              • 如果我在生产代码中发现这种过载,我肯定会将其标记为错误并尽快修复它。 + 的语义不是使值变为正数,而是保持其符号不变。
              【解决方案15】:

              只是用来说服哪些数字是正数

              例如;

              int a=10;
              System.out.println(+x);// prints 10(that means,that number 10 multiply by +1,{10*+1})
              
              //if we use unary minus
              
              int a=10;
              System.out.println(-x);//prints -10(that means,that number 10 multiply by +1,{10*-1})
              

              【讨论】:

                猜你喜欢
                • 2013-05-14
                • 1970-01-01
                • 1970-01-01
                • 2010-09-14
                • 2011-01-24
                • 2010-09-08
                相关资源
                最近更新 更多