C语言数组操作和指针操作谁更高效
在上一篇博文 代码优化小技巧(持续更新......) 第三条关于数组和指针谁更高效, 意犹未尽, 决定单独拉出一篇来讲
1. 数组和指针操作对比
#include <stdio.h> int main()
{
char *char_p, char_arr[]={,,};
short *short_p, short_arr[]={,,};
int *int_p, int_arr[]={,,}; char_p=char_arr;
short_p=short_arr;
int_p=int_arr; printf("111\n");
(*(char_p+)) ++;
printf("222\n");
char_arr[] ++; printf("111\n");
(*(short_p+)) ++;
printf("222\n");
short_arr[] ++; printf("111\n");
(*(int_p+)) ++;
printf("222\n");
int_arr[] ++; return ;
}
编译和反汇编
<main>:
: push %rbp
: e5 mov %rsp,%rbp
40059a: ec sub $0x60,%rsp
40059e: 8b mov %fs:0x28,%rax
4005a5:
4005a7: f8 mov %rax,-0x8(%rbp)
4005ab: c0 xor %eax,%eax
4005ad: c7 f0 movl $0x0,-0x10(%rbp)
4005b4: c6 f4 movb $0x0,-0xc(%rbp)
4005b8: c6 f1 movb $0x1,-0xf(%rbp)
4005bc: c6 f2 movb $0x2,-0xe(%rbp)
4005c0: c7 c0 movq $0x0,-0x40(%rbp)
4005c7:
4005c8: c7 c8 movw $0x0,-0x38(%rbp)
4005ce: c7 c0 movw $0x1,-0x40(%rbp)
4005d4: c7 c2 movw $0x2,-0x3e(%rbp)
4005da: c7 c4 movw $0x3,-0x3c(%rbp)
4005e0: c7 d0 movq $0x0,-0x30(%rbp)
4005e7:
4005e8: c7 d8 movq $0x0,-0x28(%rbp)
4005ef:
4005f0: c7 e0 movl $0x0,-0x20(%rbp)
4005f7: c7 d0 movl $0x2,-0x30(%rbp)
4005fe: c7 d4 movl $0x3,-0x2c(%rbp)
: c7 d8 movl $0x4,-0x28(%rbp)
40060c: 8d f0 lea -0x10(%rbp),%rax
: a8 mov %rax,-0x58(%rbp)
: 8d c0 lea -0x40(%rbp),%rax
: b0 mov %rax,-0x50(%rbp)
40061c: 8d d0 lea -0x30(%rbp),%rax
: b8 mov %rax,-0x48(%rbp)
: bf mov $0x400754,%edi
: e8 fe ff ff callq <puts@plt>
40062e: 8b a8 mov -0x58(%rbp),%rax
: c0 add $0x2,%rax
: 0f b6 movzbl (%rax),%edx
: c2 add $0x1,%edx
40063c: mov %dl,(%rax)
40063e: bf mov $0x400758,%edi
: e8 fe ff ff callq <puts@plt>
: 0f b6 f2 movzbl -0xe(%rbp),%eax
40064c: c0 add $0x1,%eax
40064f: f2 mov %al,-0xe(%rbp)
: bf mov $0x400754,%edi
: e8 fe ff ff callq <puts@plt>
40065c: 8b b0 mov -0x50(%rbp),%rax
: c0 add $0x4,%rax
: 0f b7 movzwl (%rax),%edx
: c2 add $0x1,%edx
40066a: mov %dx,(%rax)
40066d: bf mov $0x400758,%edi
: e8 e9 fd ff ff callq <puts@plt>
: 0f b7 c4 movzwl -0x3c(%rbp),%eax
40067b: c0 add $0x1,%eax
40067e: c4 mov %ax,-0x3c(%rbp)
: bf mov $0x400754,%edi
: e8 d4 fd ff ff callq <puts@plt>
40068c: 8b b8 mov -0x48(%rbp),%rax
: c0 add $0x8,%rax
: 8b mov (%rax),%edx
: c2 add $0x1,%edx
: mov %edx,(%rax)
40069b: bf mov $0x400758,%edi
4006a0: e8 bb fd ff ff callq <puts@plt>
4006a5: 8b d8 mov -0x28(%rbp),%eax
4006a8: c0 add $0x1,%eax
4006ab: d8 mov %eax,-0x28(%rbp)
4006ae: b8 mov $0x0,%eax
4006b3: 8b 4d f8 mov -0x8(%rbp),%rcx
4006b7: 0c xor %fs:0x28,%rcx
4006be:
4006c0: je 4006c7 <main+0x131>
4006c2: e8 a9 fd ff ff callq <__stack_chk_fail@plt>
4006c7: c9 leaveq
4006c8: c3 retq
4006c9: 0f 1f nopl 0x0(%rax)
x86编译和反汇编
0000842c <main>:
842c: e92d4800 push {fp, lr}
: e28db004 add fp, sp, #
: e24dd038 sub sp, sp, # ; 0x38
: e3a03000 mov r3, #
843c: e50b3018 str r3, [fp, #-] ; 0xffffffe8
: e3a03000 mov r3, #
: e54b3014 strb r3, [fp, #-] ; 0xffffffec
: e3a03001 mov r3, #
844c: e54b3017 strb r3, [fp, #-] ; 0xffffffe9
: e3a03002 mov r3, #
: e54b3016 strb r3, [fp, #-] ; 0xffffffea
: e24b3024 sub r3, fp, # ; 0x24
845c: e3a02000 mov r2, #
: e5832000 str r2, [r3]
: e2833004 add r3, r3, #
: e3a02000 mov r2, #
846c: e5832000 str r2, [r3]
: e2833004 add r3, r3, #
: e3a02000 mov r2, #
: e1c320b0 strh r2, [r3]
847c: e2833002 add r3, r3, #
: e3a03001 mov r3, #
: e14b32b4 strh r3, [fp, #-] ; 0xffffffdc
: e3a03002 mov r3, #
848c: e14b32b2 strh r3, [fp, #-] ; 0xffffffde
: e3a03003 mov r3, #
: e14b32b0 strh r3, [fp, #-] ; 0xffffffe0
: e24b3038 sub r3, fp, # ; 0x38
849c: e3a02000 mov r2, #
84a0: e5832000 str r2, [r3]
84a4: e2833004 add r3, r3, #
84a8: e3a02000 mov r2, #
84ac: e5832000 str r2, [r3]
84b0: e2833004 add r3, r3, #
84b4: e3a02000 mov r2, #
84b8: e5832000 str r2, [r3]
84bc: e2833004 add r3, r3, #
84c0: e3a02000 mov r2, #
84c4: e5832000 str r2, [r3]
84c8: e2833004 add r3, r3, #
84cc: e3a02000 mov r2, #
84d0: e5832000 str r2, [r3]
84d4: e2833004 add r3, r3, #
84d8: e3a03002 mov r3, #
84dc: e50b3038 str r3, [fp, #-] ; 0xffffffc8
84e0: e3a03003 mov r3, #
84e4: e50b3034 str r3, [fp, #-] ; 0xffffffcc
84e8: e3a03004 mov r3, #
84ec: e50b3030 str r3, [fp, #-] ; 0xffffffd0
84f0: e24b3018 sub r3, fp, #
84f4: e50b3008 str r3, [fp, #-]
84f8: e24b3024 sub r3, fp, # ; 0x24
84fc: e50b300c str r3, [fp, #-]
: e24b3038 sub r3, fp, # ; 0x38
: e50b3010 str r3, [fp, #-]
: e59f00b0 ldr r0, [pc, #] ; 85c0 <main+0x194>
850c: ebffff8f bl <_init+0x20>
: e51b3008 ldr r3, [fp, #-]
: e2833002 add r3, r3, #
: e5d32000 ldrb r2, [r3]
851c: e2822001 add r2, r2, #
: e20220ff and r2, r2, # ; 0xff
: e5c32000 strb r2, [r3]
: e59f0094 ldr r0, [pc, #] ; 85c4 <main+0x198>
852c: ebffff87 bl <_init+0x20>
: e55b3016 ldrb r3, [fp, #-] ; 0xffffffea
: e2833001 add r3, r3, #
: e20330ff and r3, r3, # ; 0xff
853c: e54b3016 strb r3, [fp, #-] ; 0xffffffea
: e59f0078 ldr r0, [pc, #] ; 85c0 <main+0x194>
: ebffff81 bl <_init+0x20>
: e51b300c ldr r3, [fp, #-]
854c: e2833004 add r3, r3, #
: e1d320b0 ldrh r2, [r3]
: e2822001 add r2, r2, #
: e1a02802 lsl r2, r2, #
855c: e1a02822 lsr r2, r2, #
: e1c320b0 strh r2, [r3]
: e59f0058 ldr r0, [pc, #] ; 85c4 <main+0x198>
: ebffff78 bl <_init+0x20>
856c: e15b32b0 ldrh r3, [fp, #-] ; 0xffffffe0
: e2833001 add r3, r3, #
: e1a03803 lsl r3, r3, #
: e1a03823 lsr r3, r3, #
857c: e14b32b0 strh r3, [fp, #-] ; 0xffffffe0
: e59f0038 ldr r0, [pc, #] ; 85c0 <main+0x194>
: ebffff71 bl <_init+0x20>
: e51b3010 ldr r3, [fp, #-]
858c: e2833008 add r3, r3, #
: e5932000 ldr r2, [r3]
: e2822001 add r2, r2, #
: e5832000 str r2, [r3]
859c: e59f0020 ldr r0, [pc, #] ; 85c4 <main+0x198>
85a0: ebffff6a bl <_init+0x20>
85a4: e51b3030 ldr r3, [fp, #-] ; 0xffffffd0
85a8: e2833001 add r3, r3, #
85ac: e50b3030 str r3, [fp, #-] ; 0xffffffd0
85b0: e3a03000 mov r3, #
85b4: e1a00003 mov r0, r3
85b8: e24bd004 sub sp, fp, #
85bc: e8bd8800 pop {fp, pc}
85c0: 000086a0 .word 0x000086a0
85c4: 000086a4 .word 0x000086a4
arm编译和反汇编
横向对比:

这里可以很明显得出结论: 使用数组操作比指针高效!, 理由很简单, 编译器认为数组偏移多少成员其对于地址都是确定的, 取数组[0]和[3]没有区别就是个地址, 而指针偏移是一个独立行为,
所以要显性执行这个动作, 因此多出这部分指令!
这个表还有其他有意思的地方, 比如用int变量比char、short高效, char要and或者movzbl屏蔽溢出, short要lsl/lsr左移右移等
另外就是x86可以直接通过mov操作内存, 而ARM结构采用load-store, 必须先加载到寄存器, 进行操作后再回写内存
2. 指针作为函数参数(x86编译为例)
#include <stdio.h> void test1(int *p)
{
(*(p+))++;
} void test2(int *p)
{
p[]++;
} int main()
{
char *char_p, char_arr[]={,,};
short *short_p, short_arr[]={,,};
int *int_p, int_arr[]={,,}; char_p=char_arr;
short_p=short_arr;
int_p=int_arr; /* 省略上面测试代码*/ printf("333\n");
test1(int_p);
test2(int_p);
printf("444\n");
test1(int_arr);
test2(int_arr); return ;
}
可以发现test1()、test2()反汇编实现是一样的, 不会因为“形式”上我用数组还是指针, 最终的本质是指针, 而调用无论传的是数组地址还是指针地址, 没有影响, 都是地址值而已
<test1>:
: push %rbp
: e5 mov %rsp,%rbp
40059a: 7d f8 mov %rdi,-0x8(%rbp)
40059e: 8b f8 mov -0x8(%rbp),%rax
4005a2: c0 add $0x10,%rax
4005a6: 8b mov (%rax),%edx
4005a8: c2 add $0x1,%edx
4005ab: mov %edx,(%rax)
4005ad: nop
4005ae: 5d pop %rbp
4005af: c3 retq 00000000004005b0 <test2>:
4005b0: push %rbp
4005b1: e5 mov %rsp,%rbp
4005b4: 7d f8 mov %rdi,-0x8(%rbp)
4005b8: 8b f8 mov -0x8(%rbp),%rax
4005bc: c0 add $0x10,%rax
4005c0: 8b mov (%rax),%edx
4005c2: c2 add $0x1,%edx
4005c5: mov %edx,(%rax)
4005c7: nop
4005c8: 5d pop %rbp
4005c9: c3 retq 4006e7: e8 fd ff ff callq <puts@plt>
4006ec: 8b b8 mov -0x48(%rbp),%rax
4006f0: c7 mov %rax,%rdi
4006f3: e8 9e fe ff ff callq <test1>
4006f8: 8b b8 mov -0x48(%rbp),%rax
4006fc: c7 mov %rax,%rdi
4006ff: e8 ac fe ff ff callq 4005b0 <test2>
: bf e0 mov $0x4007e0,%edi
: e8 fd ff ff callq <puts@plt>
40070e: 8d d0 lea -0x30(%rbp),%rax
: c7 mov %rax,%rdi
: e8 7c fe ff ff callq <test1>
40071a: 8d d0 lea -0x30(%rbp),%rax
40071e: c7 mov %rax,%rdi
: e8 8a fe ff ff callq 4005b0 <test2>
3. 数组作为函数参数(x86编译为例)
代码和上面一样就不贴了, 只是将参数改成数组
/*
void test1(int *p)
{
(*(p+4))++;
} void test2(int *p)
{
p[4]++;
}
*/
void test1(int p[])
{
(*(p+))++;
} void test2(int p[])
{
p[]++;
}
反汇编的结果发现和上面函数形参是指针的一模一样! 也就是说虽然我的参数看起来像数组, 但实际上由于没有指定成员数量实际分配内存, 所以编译器还是把参数当做指针对待!
结论:
a. “真实”数组操作比指针高效
b. 有些看起来像数组, 实质是指针的, 指令走的还是指针那一套, 无论语法写的是*p++还是p[i]
C语言数组操作和指针操作谁更高效的更多相关文章
- C/C++——C语言数组名与指针
版权声明:原创文章,转载请注明出处. 1. 一维数组名与指针 对于一维数组来说,数组名就是指向该数组首地址的指针,对于: ]; array就是该数组的首地址,如果我们想定义一个指向该数组的指针,我们可 ...
- 向php数组添加元素的方法哪种更高效
$arr = array(); // 第一种 array_push($arr, 'test'); // 第二种 $arr[] = 'test'; 参考PHP官方文档:http://php.net/ma ...
- C语言指针操作
欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/pointer-manipulation. ...
- 【Go语言】集合与文件操作
本文目录 1.数据集合的主要操作 1_1.字典的声明 1_2.字典的初始化和创建 1_3.字典的访问和操作 1_4.其他类型的数据集 2.文件操作 2_1.文件操作概述os包和path包 2_2.文件 ...
- C语言 数组名不是指针
今天上计算机系统课的时候老师讲到了C中的聚合类型的数据结构.在解释数组名的时候说"数组名是一个指针,指向该数组的第一个元素",附上ppt(第二行): 我觉得这是不正确的,是一个常见 ...
- 深入解析C语言数组和指针
概述 指针是C语言的重点,同时也是让初学者认为最难理解的部分.有人说它是C语言的灵魂,只有深入理解指针才能说理解了C语言.暂且撇开这些观点不谈.这章是我在阅读<C和指针>这本书的读书笔记. ...
- 【嵌入式开发】C语言 内存分配 地址 指针 数组 参数 实例解析
. Android源码看的鸭梨大啊, 补一下C语言基础 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/detai ...
- 别人不会给你说的---C语言中数组名和指针的区别 及 sizeof用法
引自: http://blog.csdn.net/tianyue168/article/details/5781924 #i nclude <iostream.h> int main( ...
- C语言 内存分配 地址 指针 数组 参数 实例解析
. Android源码看的鸭梨大啊, 补一下C语言基础 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/detai ...
随机推荐
- Capslock+ 键盘党都爱的高效利器 - 让 Windows 快捷键操作更加灵活强大
Capslock+ 键盘党都爱的高效利器 - 让 Windows 快捷键操作更加灵活强大 优化辅助 Windows 2016-06-05 91,167 微博微信QQ空间印象有道邮件 ...
- 【C语言编程练习】5.7填数字游戏求解
之前的东西就不上传了,大致就跟现在的一样 1. 题目要求 计算 ABCD * E DCBA 这个算式中每个字母代表什么数字? 2. 题目分析 如果是我们人去做这道题会怎么办,一定是这样想把,一个四位 ...
- web应用、HTTP协议及web框架简介
1. web应用 1.1 web应用程序 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件 B/S模式(浏览器/服 ...
- 蛤?你要用html做游戏?(笔记版)
标签(空格分隔):canvas html game 本书是看<html5 Canvas游戏开发实战>(2013)笔记 博主小白,啥也不懂类型,这只是一个笔记,需要的话可以看原书. 书张这样 ...
- BZOJ 3864
dp of dp 我就是来贴个代码 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a ...
- [转]C# 使用Conditional特性而不是#if条件编译
转自: http://www.cnblogs.com/xibei666/p/5495561.html 概述 #if/#endif 语句常用来基于同一份源码生成不同的编译结果,其中最常见的就是debug ...
- 分布式版本控制系统Git的安装与使用
分布式版本控制系统Git的安装与使用 作业要求来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 我的远端仓库地址是:htt ...
- 权限组件之rbac
rbac:基于角色的权限访问控制(Role-Based Access Control). rbac的主要流程:给每个角色赋予不同的权限,是这个角色的员工都有这个角色的所有权限.一个角色可以有多个人员担 ...
- NeuChar 平台使用及开发教程(三):使用 NeuChar 的菜单服务
上一篇<NeuChar 平台使用及开发教程(二):设置平台账号>我们已经完成了平台账号的设置,下面就马上来体验一下自定义菜单的设置吧! 进入某个 Neural Cell 的设置界面,在右侧 ...
- 数据库sql常见优化方法
以前刚开始做项目的时候,开发经验尚浅,每次遇到查询比较慢时,项目经理就会问:是不是又用select * 了?查询条件有没有加索引?一语惊醒梦中人,赶紧检查..果然如此! 有时我们写sql语句时,没有考 ...