【问题标题】:How does the C/C++ compiler distinguish the uses of the * operator (pointer, dereference operator, multiplication operator)?C/C++ 编译器如何区分 * 运算符(指针、取消引用运算符、乘法运算符)的用途?
【发布时间】:2021-01-23 05:12:29
【问题描述】:

在 C 和 C++ 语言中,编译器如何区分 * 用作指针 (MyClass* class) 和用作乘法运算符 (a * b) 或解除引用运算符 (*my_var )?

【问题讨论】:

  • 取决于它的左右两边是什么?
  • 维基百科有一篇关于经典方法的文章:lexer hack
  • @user786653 至少在 gcc 不再存在的情况下。 C++ 足够复杂,以至于经典的词法分析器无能为力。 G++ 使用手写的递归下降解析器(类似于谷歌翻译器的基础)而不是基于野牛的解析器。但总的来说,它取决于编译器的实现,只有少数人公开了这个秘密
  • 编译器区分a & b&var+aa + b&&aa && b的方式相同:一个是一元另一个是 binary 运算符。在 C++/CLI 中还有 type ^ vs a ^ btype % vs a % b
  • 没有实际的歧义需要解决。从语法中可以清楚地看出是一元运算符还是二元运算符,并且从当前的解析上下文中总是可以清楚地看出是在编写声明还是取消引用。

标签: c++ c lexer lexical-analysis c++-faq


【解决方案1】:

这取决于使用它的上下文,对于一个简单的解决方案,它查看左右单词以了解符号是什么。

语言的语法是由语法产生树定义的,它固有地赋予某些运算符的应用优先于或“优先于”其他运算符的应用。这在表达式可能不明确时特别方便(例如,使用的两个运算符由相同的词法标记表示)。

但这只是lexingparsing。任何特定操作是否在语义上实际上是有效的,直到编译后期才决定;特别是,给定两个指针xy,表达式*x *y 将无法编译,因为您不能将*x 乘以y,而不是因为在原本可能是取消引用的情况下缺少运算符然后是另一个取消引用。

在维基百科页面进一步阅读:Lexer_hack

在此Lexer-Hack Enacademic 链接上阅读其他有趣的内容。

【讨论】:

    【解决方案2】:
    • deferencing * 运算符是一元运算符,因此在琐碎的情况下编译器将应用隐式规则。例如
    int a;
    int *ptr = &a;
    *ptr = 5;
    
    • 乘法运算符* 是一个二元运算符,因此在一般情况下,只要操作数支持,编译器就会应用乘法,例如:
    int a;
    int b;
    int c = a*b;
    
    • 对于更复杂的操作,如果运算符 precedence 不够,您可能需要使用括号帮助编译器理解您的意思,例如:
      int a = 1;
      int b[2] = {2,3};
      int *aPtr = &a;
      int *bPtr = b;
      
      int c = *aPtr * *(bPtr+1);
    

    【讨论】:

    • 所以如果不是真的不要这么说;-)。通常对于函数指针,您需要括号,因为 operator()() 优先于 operator*(),但这不是*特定的。尤其是,为了防止取消引用和乘法之间的混淆,没有必要这样做。
    • 是的,确实如此;但同样,星号的不同语义之间没有混淆的危险。我认为这种混淆是不可能的,因为你不能将指针相乘(我敢打赌你可以在早期——ANSI 之前——C 的版本中)。
    猜你喜欢
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 2011-05-09
    • 1970-01-01
    相关资源
    最近更新 更多