[C语言]

&a+1在keil C51下的异常运行

[复制链接]
1035|16
手机看帖
扫描二维码
随时随地手机跟帖
luoengineer|  楼主 | 2020-8-13 09:53 | 显示全部楼层 |阅读模式

&a + 1 :取数组a的首地址,改地址的值加上sizeof(a)的值,即:&a + 5*sizeof(long),也就是下一个数组的首地址。所以下面的代码temp1=5,temp2=1,
        long  a[5] = {1,2,3,4,5};
        long  b[5] = {11,12,13,14,15};
        long  *ptr1 = ( long *)(&a + 1);
        long  *ptr2 = ( long *)(a + 1);
        long  temp1 = ptr1[-1];
        long  temp2 = ptr2[-1];


但是上面代码在keil 4 C51环境下编译运行,*ptr1和*ptr2的表现是一样的,指针都是移动指向a[1],最后temp1=1,temp2=1。

keil的这种编译方式不符合C语言的理解。
大家有何高见?



使用特权

评论回复

相关帖子

ayb_ice| | 2020-8-13 10:36 | 显示全部楼层
应该是你自己理解有问题吧,其它编译也应该是这样的

&a+1只能加一,不能指向下一单元,
你可以这样
pData = &a; pData ++;这时是指向下一单元

使用特权

评论回复
ayb_ice| | 2020-8-13 10:36 | 显示全部楼层
long  *ptr1 = ( long *)(&a【1】);

使用特权

评论回复
luoengineer|  楼主 | 2020-8-13 11:06 | 显示全部楼层
ayb_ice 发表于 2020-8-13 10:36
long  *ptr1 = ( long *)(&a【1】);

在cvi这样类似vc的开发环境下,&a+1就是指向下一个单元,见下图: 7F2D2F53-70E1-4fbb-92A9-88D8B589E32B.png

使用特权

评论回复
ayb_ice| | 2020-8-13 11:37 | 显示全部楼层
luoengineer 发表于 2020-8-13 11:06
在cvi这样类似vc的开发环境下,&a+1就是指向下一个单元,见下图:

keil不也是这样的吗,
那就是我的理解错了,不建议写这样的程序,按规范的方法写

使用特权

评论回复
luoengineer|  楼主 | 2020-8-13 17:13 | 显示全部楼层
2个不同的编译器造成了不同的结果,keil的工程师来解释一下就好了。

使用特权

评论回复
diweo| | 2020-8-14 10:43 | 显示全部楼层
C语言虽然有标准,但也还是有很多东西是未定义的。也就是说编译器厂商可以有一些自由发挥的余地。
这个没什么解释不解释的,你觉得合理就用,你觉得不合理就别用。

使用特权

评论回复
ayb_ice| | 2020-8-14 11:09 | 显示全部楼层
不应该一样吗
对于数组a和&a都是指地址

使用特权

评论回复
评论
xyz549040622 2020-8-15 23:25 回复TA
我一直用MDK,没用过其他环境,感觉这样很正常呀。倒是指针下标ptr[-1]这个做法,确实没用过。一直都是ptr--;或者ptr-=1;这样使用的。 
oufuqiang| | 2020-8-14 13:56 | 显示全部楼层
好奇怪的写法,楼主打算出题搞倒学生吗?还是准备拿这种题面试别人

使用特权

评论回复
William1994| | 2020-8-15 17:20 | 显示全部楼层
luoengineer 发表于 2020-8-13 11:06
在cvi这样类似vc的开发环境下,&a+1就是指向下一个单元,见下图:

a就是&a,所有的编译器都是这样的。
cvi不应该有这种低级错误啊。

使用特权

评论回复
William1994| | 2020-8-15 17:33 | 显示全部楼层
c++ builder 认为 long a[4]={9,2,3,4}; 后,a的类型是长度为4*4=16字节的一个类型,这个类型加1就是指针加16个字节。

add1.png


使用特权

评论回复
john_lee| | 2020-8-15 22:51 | 显示全部楼层
keil的编译器bug。

使用特权

评论回复
xyz549040622| | 2020-8-15 23:28 | 显示全部楼层
john_lee 发表于 2020-8-15 22:51
keil的编译器bug。

李老师的意思是,mdk这么做反而是不符合c语言规范的吗?

使用特权

评论回复
xyz549040622| | 2020-8-15 23:30 | 显示全部楼层


&a + 1 :取数组a的首地址,改地址的值加上sizeof(a)的值,即:&a + 5*sizeof(long),也就是下一个数组的首地址。所以下面的代码temp1=5,temp2=1,
        long  a[5] = {1,2,3,4,5};
        long  b[5] = {11,12,13,14,15};
        long  *ptr1 = ( long *)(&a + 1);
        long  *ptr2 = ( long *)(a + 1);
        long  temp1 = ptr1[-1];
        long  temp2 = ptr2[-1];
楼主这里的        long  *ptr1 = ( long *)(&a + 1);
改为 long  *ptr1 = ( long *)(&a + 5*sizeof(long));应该结果就是5了吧。

使用特权

评论回复
john_lee| | 2020-8-16 01:29 | 显示全部楼层
C的变量,不论是“标量类型(scalar type)”还是“聚合类型(aggregate type)”,对其取地址得到的指针,都是该变量本身类型的指针,那么对该指针做算数加减运算,单位就是sizeof(变量类型)。

例如:
// 1 ------
char a;                 // char变量,标量类型
char* p = &a + 2;       // 指针值为a的地址+偏移量sizeof(char) * 2
// 2 ------
struct a_t {
  char x[2];
};
struct a_t a;           // struct变量,聚合类型
struct a_t* p = &a + 1; // 指针值为a的地址+偏移量sizeof(struct a_t) * 2
// 3 ------
char a[4];    // 数组变量,聚合类型
char (*p)[4] = &a + 2;  // 指针值为a的地址+偏移量sizeof(char[4]) * 2

上面所说的聚合类型不包括“未指定边界的数组(array with unspecified bounds)”,未指定边界的数组也可以取地址,由于数字大小未知,所以其指针不允许做加减运算,只能用作访问数组元素。
例如上面的例子3就是一个已指定数组边界的数组,如果紧接着写:
p++;                    // 合法,指针值为a的地址+偏移量sizeof(char[4]) * 3

而:
char a[4];
char (*p)[] = &a + 2;   // 未指定数组边界的数组指针,指针值为a的地址+偏移量sizeof(char[4]) * 2
(*p)[1] = 1;            // 合法,访问数组元素,赋值地址为a的地址+偏移量(sizeof(char[4]) * 2) + sizeof(char),注意:访问的地址已越界
p++;                    // 非法

使用特权

评论回复
john_lee| | 2020-8-16 11:14 | 显示全部楼层
本帖最后由 john_lee 于 2020-8-16 11:18 编辑

C的变量,不论是“标量类型(scalar type)”还是“聚合类型(aggregate type)”,对其取地址得到的指针,都是该变量本身类型的指针,那么对该指针做算数加减运算,单位就是sizeof(变量类型)。

例如:
// 1 ------
char a;                 // char变量,标量类型
char* p = &a + 2;       // 指针类型为char,值为a的地址+偏移量sizeof(char) * 2
// 2 ------
struct a_t {
  char x[2];
};
struct a_t a;           // struct变量,聚合类型
struct a_t* p = &a + 1; // 指针类型为a_t,值为a的地址+偏移量sizeof(struct a_t) * 2
// 3 ------
char a[4];              // 数组变量,聚合类型
char (*p)[4] = &a + 2;  // 指针类型为char[4],值为a的地址+偏移量sizeof(char[4]) * 2
上面所说的聚合类型不包括“未指定边界的数组(array with unspecified bounds)”,未指定边界的数组也可以取地址,由于数字大小未知,所以其指针不允许做加减运算,只能用作访问数组元素。
例如上面的例子3就是一个已指定数组边界的数组,如果紧接着写:
p++;                    // 合法,指针值为a的地址+偏移量sizeof(char[4]) * 3
而:
char a[4];
char (*p)[] = &a + 2;   // 指针类型为char[],是未指定数组边界的数组指针,值为a的地址+偏移量sizeof(char[4]) * 2
(*p)[1] = 1;            // 合法,访问数组元素,赋值地址为a的地址+偏移量(sizeof(char[4]) * 2) + sizeof(char),注意:访问的地址已越界
p++;                    // 非法

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

80

帖子

1

粉丝