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 ...
随机推荐
- python练习题目
1.查看本机安装python版本 2.用python打印"Hello World",给出源代码和执行结果 a.命令行窗口输出(前提:python程序加入PATH系统环境变量) b. ...
- 201771010126 王燕《面向对象程序设计(Java)》第十四周学习总结(测试程序11)
实验十四 Swing图形界面组件 理论部分: 不使用布局管理器 有时候可能不想使用任何布局管理器,而只 是想把组件放在一个固定的位置上.下面是将一 个组件定位到某个绝对定位的步骤: 1)将布局管理器 ...
- LeetCode 80 Remove Duplicates from Sorted Array II [Array/auto] <c++>
LeetCode 80 Remove Duplicates from Sorted Array II [Array/auto] <c++> 给出排序好的一维数组,如果一个元素重复出现的次数 ...
- [bzoj1059]矩阵游戏
虽然是一道水难题,但是我这种蒟蒻还是要讲一讲的. Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际 ...
- openCV 简单实现身高测量(未考虑相机标定,windows)
(一) OpenCV3.1.0+VS2015开发环境配置 下载OpenCV安装包(笔者下载3.1.0版本) 环境变量配置(opencv安装路径\build\x64\vc14\bin,注意的是x64文件 ...
- Java和js操作json
Js中 Json字符串转json对象 //将json格式的字符串转为json对象 var t = JSON.parse('{"name":123}'); alert(t.name) ...
- Fence Repair POJ - 3253 (贪心)
Farmer John wants to repair a small length of the fence around the pasture. He measures the fence an ...
- spring MVC 的MultipartFile转File读取
转自:http://www.cnblogs.com/hahaxiaoyu/p/5102900.html 第一种方法: MultipartFile file = xxx; Commo ...
- jsp中input获得后台传递的值
1.后台赋值 req.setAttribute("openId",openId); 2.前台获取值 value="<%= request.getAttribute( ...
- 搭建一个舒适的 .NET Core 开发环境
最近,一直在往.Net Core上迁移,随着工作的深入,发现.Net Core比.Net Framework好玩多了.不过目前还在windows下开发,虽然VisualStudio是宇宙第一神器,但是 ...