C++ 是C++;编译器真的足够聪明来区分乘法和去引用吗?

C++ 是C++;编译器真的足够聪明来区分乘法和去引用吗?,c++,lexical-analysis,C++,Lexical Analysis,我有以下代码行: double *resultOfMultiplication = new double(*num1 * *num2); 编译器如何知道哪个*用于解除保护,哪个*用于乘法 另外,可能还有一个更重要的问题,在本例中,double是原语(如Java)还是对象?如果它是一个原语,我如何才能创建一个新的原语呢?首先是取消引用,因此*num1**num2被解析为(*num1)*(*num2),这是明确的*resultOfMultiplication不被解析为解引用,因为它是一个变量定义。

我有以下代码行:

double *resultOfMultiplication = new double(*num1 * *num2);
编译器如何知道哪个
*
用于解除保护,哪个
*
用于乘法


另外,可能还有一个更重要的问题,在本例中,
double
是原语(如Java)还是对象?如果它是一个原语,我如何才能创建一个新的原语呢?

首先是取消引用,因此
*num1**num2
被解析为
(*num1)*(*num2)
,这是明确的
*resultOfMultiplication
不被解析为解引用,因为它是一个变量定义。在这样的上下文中,编译器需要一个后跟标识符的数据类型,因此星号是明确的


原始数据类型仍然是C++中的对象。如果对原语类型使用

new
,所发生的只是在空闲存储区中分配了足够的内存来存放对象,并将其地址返回给您。这与“普通”变量(即
双t;
)不同,后者具有自动或静态存储持续时间。

编译器不需要“智能”;语言的语法是由一个语法生成树定义的,它固有地赋予某些运算符的应用优先于其他运算符的应用。当表达式可能不明确时(例如,使用的两个运算符由同一个词法标记表示),这尤其方便

但这只是词法分析和解析。任何特定的操作是否在语义上是有效的,直到编译的后期才决定;特别是,给定两个指针
x
y
,表达式
*x*y
将无法编译,因为您不能用
*x
乘以
y
,而不是因为在一个解引用之后可能发生的另一个解引用中缺少运算符


<>我没有深入地证明C++中存在操作符优先权;为此,只要上一门语法结构的基础课,你很快就会学好的。

都是关于语法的。没有后缀
*
,因此标识符后的
*
必须被视为中缀乘法。

也许一个类比会有所帮助:

问:人类如何区分“i”上面的点和句子末尾的点?他们真的那么聪明,不把每一个“我”都解释为句子的结尾吗

因为他们在不同的地方

编译器的“*”也是如此:它们出现在不同的位置。乘法运算符位于两个表达式的中间;解引用运算符位于表达式前面。这对您来说可能并不明显,但对编译器来说却是显而易见的

任何关于解析的合适文本都会告诉您编译器是如何做到这一点的。所需的技术大约是40年前开发的,被认为是编译器中最基本的东西之一。C++编译器必须有许多智能部件,但这不是其中之一。
专家注意:我知道因素、左值等。但在这种情况下,它们只会混淆。

因为问题是关于“智能性”,我想补充一点。我的答案是C语言,但是我假设C++中的情况是相同的。 在这种情况下,编译器不需要真正聪明,因为语言不允许直接对地址执行乘法,因此指针前面的符号
*
始终只能表示“解引用”,而非指针前面的符号
*
只能表示“乘法”

我将尝试用一个例子来解释这一点

让我们创建一个小程序,并将其命名为
test.c
。然后,让我们在
main()
函数中创建两个指针
first
second
,并将
first
的地址设为
140732806008300
,将
second
的地址设为
140732806008296

当我们尝试对两个地址求和时,编译器允许我们和平地使用
+
操作数,而无需进行前一次强制转换,因为在C中,指针的和是允许的:

#包括
int main(){
整数*第一,*第二,十五=15,二十=20;
first=&十五;/*让'first'的地址为140732806008300*/
second=&twenth;/*设'second'的地址为140732806008296*/
printf(“第一个+第二个是:%llu\n”,(长无符号整数)第一个+第二个);
返回0;
}
我们在这里所做的是直接执行两个指针的求和,得到一个新指针,然后为了
prinf()
函数的缘故,它被转换成一个无符号整数。因为这是允许的,所以我们正确地获取字符串

first + second is: 703664030041496
但是,如果我们尝试使用乘法操作数
*

#包括
int main(){
整数*第一,*第二,十五=15,二十=20;
first=&十五;/*让'first'的地址为140732806008300*/
second=&twenth;/*设'second'的地址为140732806008296*/
printf(“第一*秒为:%llu\n”,(长整型无符号整数)第一*秒);
返回0;
}
…我们得到以下错误:

test.c: In function ‘main’:
test.c:11:69: error: invalid operands to binary * (have ‘long long unsigned int’ and ‘int *’)
  printf("first * second is: %llu\n", (long long unsigned int) first * second);
这是因为地址的直接乘法是不允许的。因此,我们必须将指针转换为有效整数,才能最终使用具有“乘法操作数”含义的符号
*

#包括
int main(){
整数*第一,*第二,十五=15,二十=20;
first=&十五;/*让'first'的地址为140732806008300*/
second=&twenth;/*设'second'的地址为140732806008296*/
printf(“第一个*第二个是:%llu\n”,(长时间未在中签名)
first * second is: 4480243502683625952