指针声明与乘法表达式的区分及C语言中a * b;语句的语法解析疑问
这个问题问得特别到位,刚好命中了C语言语法里一个容易让人懵圈的细节——编译器到底是先把语句当声明还是表达式来解析。咱们结合C标准的语法规则,一步步把这个问题拆透:
首先得记住C语法解析的核心优先级规则:编译器会优先尝试把语句解析成声明,只有当声明路径完全走不通的时候,才会退而求其次当作表达式处理。这是判断的大前提。
接下来分两种核心场景来看:
当
a是已定义的类型名时
比如你之前写过typedef int a;,或者a是某个struct/union的标签(比如struct a { int x; };),那编译器走声明解析路径会完全合法:a作为类型说明符,*是指针修饰符,b是被声明的标识符。这时候a * b;会被解析成「声明一个指向a类型对象的指针变量b」。哪怕你之前已经声明过b,编译器也会先按声明来处理,这时候可能会报「重定义/重复声明」的错误,而不是当作乘法表达式。当
a不是类型名时
如果a只是普通变量(比如你声明过int a;),或者压根没定义过,那编译器尝试解析成声明就会失败——因为a没法被识别为合法的类型说明符。这时候它才会切换到表达式解析路径,把a * b;当作「a乘以b,然后丢弃运算结果」的无效果表达式。
这时候如果a或b没被声明过,编译器会报「未声明的标识符」错误;如果两者都已声明,大部分编译器会抛出「表达式结果未被使用」的警告,提醒你这个语句没有实际作用。
还要补充一个容易踩坑的点:如果a同时被定义为类型名和变量名(比如typedef int a; int a;),这时候在变量a的作用域里,编译器会优先把a当作变量名,所以a * b;会被解析成乘法表达式,而不是指针声明——因为这时候走声明路径的话,a不是合法的类型说明符(变量名覆盖了类型名的可见性)。
总结一下就是:a * b;的解析结果完全取决于a是否能被编译器识别为合法的类型说明符,而编译器的判断逻辑是「先声明,后表达式」,这是C标准规定的语法解析顺序。
内容来源于stack exchange

