C/C++编译器如何区分*运算符的不同用法(指针、取值运算符、乘法运算符)?

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

2
维基百科上有一篇关于经典方法的文章:词法分析器 hack - user786653
2
@user786653,至少在gcc的情况下,这已经不再是一个问题了。C++足够复杂,以至于传统的词法分析器无法胜任。G++使用手写递归下降解析器(类似于Google翻译基础中使用的东西),而不是基于bison的解析器。但总的来说,这取决于编译器的实现,只有少数人揭示了这个秘密。 - Swift - Friday Pie
4
编译器区分 a & b&var+aa + b&&aa && b 的方式相同:一个是一元运算符,另一个是二元运算符。在C++/CLI中也有 type ^a ^ btype %a % b - phuclv
@Swift-FridayPie gcc和clang都是开源的,所以这里几乎没有什么秘密。 - M.M
1
没有实际的歧义需要解决。从语法上看,一元运算符或二元运算符的意图总是清晰明了的,并且从当前解析上下文中也很清楚是在编写声明还是解引用。 - user207421
2个回答

20

它的含义取决于使用的上下文,对于简单的解析,它会查看左右单词以了解符号的含义。

编程语言的语法由一棵语法产生树定义,其天然地将某些运算符的应用优先级或“优先级”融入其中,这在表达式可能模棱两可时特别有用(比如说两个使用相同词汇标记的运算符)。

但这仅仅是词法分析和语法分析。任何特定操作是否实际上具有语义有效性要到后面进行编译才能确定;特别地,对于给定的两个指针 xy,表达式*x *y将无法编译,因为你不能将*x乘以y,而不是因为在可能是一个解引用后跟另一个解引用的情况下缺少运算符。

更多阅读请参考维基百科页面:Lexer_hack

此外,还可以在这个Enacademic链接中了解其他有趣的内容。


5
  • 解引用*操作符是一元操作符,所以在简单情况下编译器会应用隐式规则。例如
int a;
int *ptr = &a;
*ptr = 5;
  • 乘法运算符*是一个二元运算符,因此在简单的情况下,编译器会应用乘法,前提是操作数支持它,例如:
int a;
int b;
int c = a*b;
  • 对于更复杂的操作,如果运算符优先级不足以理解你的意思,你可能需要使用括号来帮助编译器理解:
  int a = 1;
  int b[2] = {2,3};
  int *aPtr = &a;
  int *bPtr = b;
  
  int c = *aPtr * *(bPtr+1);

所以如果不是真的,请不要说。通常情况下,对于函数指针,您需要使用括号,因为operator()()的优先级高于operator(),但这并非特定。特别地,在防止解引用和乘法之间的混淆方面,这并不是必需的。 - Peter - Reinstate Monica
是的,确实如此;但是再次强调,星号具有不同语义的情况下不会产生混淆的危险。我想混淆是不可能的,因为您不能乘以指针(我敢打赌,在早期的ANSI之前的C版本中可能可以这样做)。 - Peter - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接