免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: pmerofc

[C] 请教一个基础问题——数组名减1是否可以 [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
发表于 2009-12-16 04:04 |显示全部楼层

回复 #30 ZSMDEV 的帖子

嗯, 这样才更有意义

1. 不采用标准手段
2. 自己臆测
3. 出现莫名错误
4. 论坛发帖求助
5. 胡乱修改
6. 移植到其他平台继续出错
7. 重复4
8. 永远执行不到这里, 嗯,死循环了。


1、2、3、4 :
原帖由 ZSMDEV 于 2009-12-15 10:20 发表
void fun(int a, ...)
{
  int *temp = &a;
  temp++;
  for(int i = 0;i < a; ++i)
  {
    printf("%d ", *temp);
    temp++;
  }
  printf("\n");
}



5、6、7:
原帖由 sbc19861004 于 2009-12-15 12:03 发表
void fun(int a, ...)
{
  int *tmp = &a;
  tmp++;
  long long *temp = tmp;
  for(int i = 0;i < a; ++i)
  {
    printf("%d ", *temp);
    temp++;
  }
  printf("n");
}

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
发表于 2009-12-16 09:14 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
发表于 2009-12-16 10:13 |显示全部楼层
原帖由 OwnWaterloo 于 2009-12-15 21:09 发表


对, 标准就是在这里说得确实有点模糊。

标准要求: 如果结果指向数组内,或者指向数组之后一个,一定不能产生溢出。
如果不在这个范围,标准说的不是"可以溢出,允许溢出", 而是"无定义行为"。

那 ...

兄弟这个地方理解有点问题。

标准指的是不产生溢出,是指程序员明白他所做的操作的执行结果是什么。对于编译器来,说数组指针减1只是个指针运算而已,所以只要程序员明白运算后的指针指向的是合法的位置,包含合法的内容,则这个操作就是标准的做饭。
>>otherwise, the behavior is undefined
这里的otherwise指的是一旦产生溢出,则是无定义行为。标准通常将“behavior is undefined“表示为带来不可以预知结果的行为,主要强调的是操作的结果不可预知。
标准在这个问题上解释是清楚的。

我们以前内核里container_of的用法来说明在程序员控制的情况下,数组指针减是一个完全正确的操作


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stddef.h>

  4. #define container_of(ptr, type, member) ({          \
  5.         const typeof(((type *)0)->member) * __mptr = (ptr); \
  6.         (type *)((char *)__mptr - offsetof(type, member)); })

  7. struct test {
  8.     int a;
  9.     int b;
  10.     char arr[10];
  11.     int d;
  12. } x;

  13. int main() {
  14.     printf ("%p, %p\n", &x, container_of (&x.arr, struct test, arr));
  15. }
复制代码

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
发表于 2009-12-16 10:33 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
发表于 2009-12-16 10:56 |显示全部楼层
原帖由 pmerofc 于 2009-12-16 10:33 发表


我的理解和您有些不同
我认为“ shall not produce an overflow”是告戒编译器的作者这些操作不可以产生溢出,是对编译器的要求,也是对CODER的承诺
至于“只要程序员明白运算后的指针指向的是合法的位置 ...

>>我认为“ shall not produce an overflow”是告戒编译器的作者这些操作不可以产生溢出,是对编译器的要求,也是对CODER的承诺
这是不对的。编译器无法保证不溢出。这是要程序员自己保证。C编译器是不做任何边界检查之类的安全保证,实际上它也做不了(除非把C编译器改成带有runtime的功能),程序的安全性要靠程序员自己保证。


>>如果数组的位置并不是CODER自己安排的
>>那么,实际上CODER是无法“明白运算后的指针指向的是合法的位置”的
程序员总是能知道的。变量定义的位置和顺序就保证了其所在的位置。
首先定义在全局区的和static变量始终在全局区。在函数内部定义的非static变量始终在栈上。再配合周围变量的定义以及栈增长的方向,程序员就可以知道自己的操作是否越界。
例如

  1. void foo ()
  2. {
  3.       int a;
  4.       char arr[10];
  5.       int b;
  6. }

复制代码

假设栈是向下增长的,自然对齐
程序员就知道arr - 6指向的是c,不会溢出;arr+10则是指向a。但arr - 0xffffffff则一定溢出。
C的程序员需要知道自己程序的一切

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
发表于 2009-12-16 12:48 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
发表于 2009-12-16 12:53 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
发表于 2009-12-16 12:55 |显示全部楼层
"C语言本身应该构成一个封闭的逻辑体系" 我觉得至少现在还做不到,如果能够做到,就不存在undefined behavior 了

论坛徽章:
0
发表于 2009-12-16 13:07 |显示全部楼层
原帖由 pmerofc 于 2009-12-16 12:48 发表


就经验和知识的范畴来说
我同意
但就方法论的角度
我们有巨大的差异
我个人认为C语言本身应该构成一个封闭的逻辑体系
不应该用这个体系之外的概念(比如:操作系统、编译原理、汇编)来解释
“栈”这 ...

LZ可能是从其他语言转到C的,把C想像成脱离编译器、硬件纯抽象语言了。
在解释标准的时候是不应该特定于具体平台、编译器,但在举例子时却无法不牵涉到平台、编译器。
凡是是编译执行的语言,就不可能脱离硬件、编译器纯理论的构成封闭系统。

论坛徽章:
0
发表于 2009-12-16 13:20 |显示全部楼层
程序都是在假定的环境下写的。不存在没有假定条件下能写出程序的(即使写出来了,也是个废物)。讨论这些是浪费时间。

[ 本帖最后由 pagx 于 2009-12-16 13:23 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP