原来 c++竟然支持数组下标为负

2018-04-04 18:45:34 +08:00
 z0z
毫无疑问的,这暴露了我是一个 c++盲的事实。

不知道为什么我实在是有些兴奋。
5137 次点击
所在节点    分享发现
15 条回复
MeteorCat
2018-04-04 18:51:57 +08:00
其实数组是可以为负的,Redis 有数组-1 位移运算的用法,当然这种高端黑科技用法不推荐
MeteorCat
2018-04-04 18:58:33 +08:00
redis 源码的 sds.h 函数 sds_len 有这个方面实践,这算是比较偏门的黑魔法吧
z0z
2018-04-04 19:07:17 +08:00
@MeteorCat 嗯。


1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<stdint.h>
4 #include<string.h>
5
6
7 int main(void)
8 {
9 uint8_t arrary[8]={0,1,2,3,4,5,6,7};
10 uint8_t *p=&arrary[4];
11
12 printf("p[-1]=%d\n",p[-1]);
13
14 return 0;
15 }

xxxxxxx@server5:~/temp/testarray$ ./test
p[-1]=3

刚试了一下,c 也支持。
原来编译器还有这种功能。
。。。。
MeteorCat
2018-04-04 19:09:56 +08:00
@z0z 很好玩的特性,但是很容易就玩脱了,我感觉在 C++11 慢慢上来的时候,能够用 vector 这种容器就用得了
Librazy
2018-04-04 19:13:22 +08:00
C++默认的下标表达式 E1[E2] 等同于表达式 *(E1 + E2) ,所以只要解引用 E1 + E2 是合法的就可以了
Librazy
2018-04-04 19:15:39 +08:00
如何理解完全等同:试试 -1[p] 就知道了
sfqtsh
2018-04-04 19:21:26 +08:00
这都可以的:
int i = 2;
char c = "abcdefg"[i];
bumz
2018-04-04 19:33:48 +08:00
int * a = new int[4] + 2;

然后愉快地

a[-2], a[-1], a[0], a[1]

2333
aheadlead
2018-04-04 19:58:10 +08:00
火星了…

C 你写成这样也可以:

char *str="233333";
putchar(1[str]);
h4lbhg1G
2018-04-04 20:00:49 +08:00
似乎可以这么写

int a[5]={0,1,2,3,4};
2[a]=1[a]+0[a];
Akiyu
2018-04-04 20:02:13 +08:00
我也是才知道,之前没有做过这种骚操作
之所以说是"骚操作",是因为你不知道那个地址里面是什么东西,类似于按照数组的类型去解释未知内存一样

理解了原理就知道了
它是拿着那个整数做偏移,然后按照数组的类型来拿取和解释那块内存(占多大,是如何存储的)

引申:
如果对汇编感兴趣的话就知道各种数组取值的不同写法,就像楼上的 1[p]一样
idata+[寄存器], 寄存器+idata, 寄存器+寄存器+idata...(具体可能有误, 我不记得细节了
不过都是那种概念,就是表示偏移地址寻址, 本质都是一样的,具体可以参照<<汇编语言>>)

PS:
如果楼主对这方面感兴趣的话,可以看看<<汇编语言>> (汇编有 x86 和 ARM,
看完之后你会一边内心叫着 MMP, 一边想着底层真有趣)
h4lbhg1G
2018-04-04 20:06:44 +08:00
似乎可以这么写

嗯 看到上面的字符串 我想起一个黑魔法了

char* str1="12345678";
char* str2="abcdefghi";

char* p=str2;

for(int i=0;i<strlen(str1);i++)putchar((-i)[p]);
gnaggnoyil
2018-04-05 06:37:22 +08:00
@h4lbhg1G 你这么写就不对了……指针运算其结果必须要么处于合法的数组或者 malloc 出来的空间的内部,要么是这个空间紧跟着的下一个地址,否则是未定义行为.
h4lbhg1G
2018-04-20 19:29:55 +08:00
@gnaggnoyil #13 刚刚才看到 这就是假设两个字符串常量被紧凑放在内存里,如果编译器不这么按顺序连续分配内存(不太清楚 C 标准具体有没有规定)当然就不行了。

有点函数内部用内联汇编的感觉吧。虽然我是感觉这种代码顶多只会在逆向破解的 poc 程序中出现
gnaggnoyil
2018-04-20 19:42:59 +08:00
@h4lbhg1G
>如果编译器不这么按顺序连续分配内存(不太清楚 C 标准具体有没有规定)

当然没有.这玩意在标准中如果不是 implementation defined 那就是 unspecified.不过这不是关键点.关键点在于,只要你这段代码出现了越界的未定义行为,不管这两段 storage 的排列是如何,编译器的最终行为也是没有定义,不可预料的.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/444376

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX