1. 首页
  2. Go每日一题

Go每日一题(68) 的题目如下

4788 次点击 · 3 赞 · 开始浏览 · 来源「公众号「polarisxu」」

Go101 发布的一条 twitter。以下代码是否能正常运行,结果是?

package main
func main() {
 v := new(int)
 *v = 2
 println(5/+-*v)
}

答案解析:

大家肯定很懵。我看到时也蒙圈了。

试着运行了一下,竟然输出了 -2 。。。我忍不住"卧槽"。。。

我不得不说,Go101 扣的真细节。

于是我尝试着找一些线索,看看为什么可以这样写。

01 直接看汇编

遇到一些不解的地方,有时候借助汇编也许能得到答案:

go tool compile -S main.go

看关键的几行汇编:

	0x001d 00029 (main.go:6)	PCDATA	1,ドル 0ドル
	0x001d 00029 (main.go:6)	NOP
	0x0020 00032 (main.go:6)	CALL	runtime.printlock(SB)
	0x0025 00037 (main.go:6)	MOVQ	$-2, (SP)
	0x002d 00045 (main.go:6)	CALL	runtime.printint(SB)
	0x0032 00050 (main.go:6)	CALL	runtime.printnl(SB)
	0x0037 00055 (main.go:6)	CALL	runtime.printunlock(SB)

MOVQ $-2, (SP) 看出,直接编译器直接计算出 -2 了。。。(可以进一步加上 -N 来禁止优化,但没有没有看出额外特别的)

02 看规范

之前的一些题解,我总是在 Go 语言规范中找到解释,因此这次也不例外。

在运算符章节,Go 中有如下几个一元运算符:

unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

其中,+、- 和 * 同时也是算术运算符中的加、减和乘。

接着,在运算符优先级处提到:一元运算符有最高的优先级。

我们分析题目中的表达式:5/+-*v。5 后面 /,很显然,这是除法。而 + 前面没有操作数,因此是一个一元运算符;同理 - 和 * 也是一元运算符。而一元运算符有最高的优先级,因此这个表达式优先计算 +-*v 的值。那这个东西为什么又合法呢?

在规范中有这么一句话:

对于整数操作数,一元运算符 + , -^ 有如下定义:(省略了 ^ 的解释)

+x 是 0 + x
-x 取其负值 是 0 - x

也就是说,+-*v 相当于:0+(0-(*v))。(为什么一元运算符左结合,因为一元,必须得有运算数,得跟着运算数走)

这样一来,结果变成了求 5/-2 的值,结果自然是 -2(别跟我说应该是 2.5)。

(规范参考 Bekcpear 翻译版:https://hao.studygolang.com/golang_spec.html)

03 其他语言的行为

看到这,我不禁想看看其他语言怎么实现的。(没有指针的语言,就只能包含 /+- 了)

C 语言

#include <stdio.h>
int main()
{
		int i = 2;
 	int *p = &i;
 	printf("%d\n", 5/+-*p);
 	return 0;
}

结果也是 -2。

Java

public class HelloWorld {
 public static void main(String []args) {
 System.out.println(5/+-2);
 }
}

结果也是 -2。

PHP

<?php
echo 5/+-2;

结果是 -2.5。(弱类型语言嘛)

Python

5/+-2

结果是 -3。(Python 对 / 的处理和别的语言还是不太一样)

JS

5/+-2

结果和 PHP 一样,-2.5。

最后看看 Rust

fn main() {
 println!(5/+-2);
}

编译器告诉我:

error: expected expression, found `+`

Rust 果然不一样!我们不一样、不一样。。。

04 总结

奇淫技巧,如果能顺便学一点知识,那是极好的。当然,最关键的是希望有探索精神,找到其中的原因,举一反三,也许这点比较重要。

题解来自:https://polarisxu.studygolang.com/posts/go/action/operator/

4788 阅读
35 回复
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册

今日阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)