按照古老的汇编知识,编译器应该是把 #define 做直接的替换,然后汇编指令里使用立即数,避免了一次mov操作,进而得到更高的性能。而定义变量的方式,则一方面会占用内存,计算时还需要将数据从内存mov到寄存器,所以会慢一些。
可惜我使用了gcc在x86_64、arm、avr上的三个版本以及各种优化选项。得到的结果都没有找到将 #define作为汇编立即数的玩法。而是都是定义一个区域后,当作全局变量/静态变量的方式,再mov到寄存器使用的。
开始还怀疑只是浮点数会有这个问题,后来换了整数发现还是这样。gcc还是让我很失望的。
立即数是指做计算时的一个操作数是直接写在指令里的,而非在寄存器里,这样会节省内存和寄存器资源,避免了缓慢的内存倒腾寄存器过程。在高性能计算过程会有很大的性能提升。只是可惜我在gcc里没能复现出这个本该出现的优化。
如下是我写的测试用的C程序 definef.c:
#include <stdio.h>
#define PI_D 3.1416
#define TEN 10
float calc1(float factor) {
return (TEN * factor);
}
float calc2(float factor) {
//float PI_V=3.1416;
int ten=10;
return (ten * factor);
}
int main() {
//printf("%f, %f ", calc1(), calc2());
calc1(2030);
calc2(2030);
return 0;
}
编译到汇编的命令:
gcc -S definef.c
随后可以打开文件 definef.s 来查看生成的汇编代码:
.file "definef.c"
.text
.globl calc1
.type calc1, @function
calc1:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss %xmm0, -4(%rbp)
movss -4(%rbp), %xmm1
movss .LC0(%rip), %xmm0
mulss %xmm1, %xmm0
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size calc1, .-calc1
.globl calc2
.type calc2, @function
calc2:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss %xmm0, -20(%rbp)
movl $10, -4(%rbp)
pxor %xmm0, %xmm0
cvtsi2ss -4(%rbp), %xmm0
mulss -20(%rbp), %xmm0
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size calc2, .-calc2
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movss .LC1(%rip), %xmm0
call calc1
movss .LC1(%rip), %xmm0
call calc2
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE2:
.size main, .-main
.section .rodata
.align 4
.LC0:
.long 1092616192
.align 4
.LC1:
.long 1157480448
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits
从如上calc1标签可见。#define常量放在了标签 .LC0 里,随后被载入到了寄存器%xmm0。
真可惜,不过也越发激励了我的一个业余项目。给Python里内嵌汇编JIT的功能。使得可以直接写一段汇编代码并在运行时编译成可执行代码供优化性能。只要利用Python的格式化字符串来传入那些必要的变量到汇编立即数,就能获得比C/C++更高的性能了。
优势就是前者可以兼容double跟float,甚至字符串,而且是编译期转换。
后者用float损失了精度。而且用到不同类型比如字符串时需要运行期转换。
浮点如果直接定义为const有类型常量通常需要定义两份,一份float一份double。而使用define这样的无类型常量定义就只需要定义一份。
之所以这样是因为浮点跟整数不同,整数类型之间转换是直接截断,没有开销。浮点类型之间转换是有开销的,不同浮点的存储格式不同。
我是一名基层派出所民警。
可以说当今中国警察普遍羡慕美国警察可以采取暴力手段绝对的镇压不法分子。
但是,不得不说,这次这位美国警察,太过分了,不仅是过分,而且我的理解是那已经构成了犯罪行为。那黑人已经制服了就可以正常上拷带走了,没必要一直压着脖子压那么长时间。没能置身其中不知现场那美国警察的所思所想,反正我个人挺不理解他为啥那样干的。
只能说无论什么地方,无论什么行业,只要是人的社会,都有像样的也有操蛋的吧。
_________此处为分割线 _________
以下为统一答复评论中有些人质疑的我所讲的羡慕二字。
能够出现这种质疑在我料想之中,因为中国警察也有过过分的时代,据我所知就是在七十八十九十年代,就如同地痞流氓,看谁不顺眼就能打谁对老百姓而言没王法可讲,那时候的警察说好听点可以说是威风凛凛说难听点儿是横行霸道。
但我想表明的是,时过境迁,现在的中国警察无论是受舆论约束还是因为法治社会建设制度规范都已经变得逐步文明与规范起来,起码我认为从我们现在开始从公安司法院校毕业参加公务员考试考进来的新一代警察已经具备新的面目,当然不可否认的是在这个行业内目前仍然存有历史的顽疾,仍然存在着臭虫,但我已经讲过无论什么行业都有操蛋的吧,这是个人问题,不是群体问题。相比之下,拍拍良心看,现在的整个警察队伍比照曾经确实过分的年代是不是已经是天地之别,问问曾经真正挨过曾经年代老警察欺负的中老年人就知道了。
为何会说起羡慕,因为警察每天面对的人群,大多是三教九流之辈,没有武力加身,很多事情在处理上警察显得软弱无能,说白了,好人谁没事儿上派出所转悠啊都忙着自己的生活呢,警察打人这句话,我们常常听到,但是但凡有点脑袋的人都能想明白,警察会闲着没事儿干把那在家里消停待着的遵纪守法的人抓起来暴揍一顿吗?
以上言辞不免更会有人质疑,请允许我解释,武力,当然不可滥用,我所说的羡慕不是羡慕美国警察的随意滥用武力,而是在合法范围内准许在对方不听从警察指令时动用武力,现在确实有人民警察法赋予了相关权力,但实践中现在的中国警察并不能或者说不敢执行人民警察法里的所有权力。拿防疫工作举例,卡口的工作人员在让出入的人员扫码登记时,就会有不愿意配合的人,然而这些不愿意配合的人可会知道工作人员的所做所为是为了整个社区的稳定安全,因为这整个社区包括了这名不愿意配合的人啊,在这个时候是否应当对其进行武力控制来保障其他居民的安全呢。同理,警察盘查也好,调查也好,总会有那些不愿意配合的人,自我感觉良好认为自己没问题所以警察不必要对其进行盘查所以就不配合,而警察当看到对方不配合时会以什么视角审视,难道要说谢谢您的不配合吗,万一这不愿配合的人真背着案子呢,那便是对更多的人民群众的不负责任。因此,我要说,民众的素质如果真正达到了人人互相敬重路不拾遗夜不闭户的文明程度,要求警察绝对文明不要有暴力举动,一点问题没有,一味强调了警察不该暴力执法而分毫不过问被执法对象自身是否存在问题,是不是看问题的角度些微的片面了些。
请注意,我说羡慕里的那句话尾巴实际已经表明了,羡慕的是暴力手段对不法分子的镇压,可不是对遵纪守法的百姓也要肆意妄为。例如像给群众办个身份证居住证之类的业务,警察当然应该热心服务。但当面对泼皮无赖时,还要笑脸相迎,得来的只有蹬鼻子上脸,警察都不怕了,您们认为这些无赖还有谁管得了。
列位存有异议的同志们,谢谢您们的教诲。言辞中犀利的同志们,谢谢您们的敦促。
让我知道当警察,需要吾日三省吾身。
还想要质疑甚或是骂的您们,若是能让您舒服,骂两句无妨。我不算您辱骂警察。不过是,道不同不相为谋罢了吧。
_____分割线
2020年6月5日22:53 出警在路上