打印

实际使用中没有问题的话,就**自己认为正确的就可以了

[复制链接]
楼主: wrainp
手机看帖
扫描二维码
随时随地手机跟帖
21
HWM| | 2008-5-16 12:58 | 只看该作者 回帖奖励 |倒序浏览

完全同意OO的说法,另外要补充的是在C中数组名其实存在二


还是再看下面的定义:

char cA[10];

若单独拿出cA来看,可以解释成指向数组首单元的常数指针(在C标准中可以找到),但若和sizeof或&结合时却表现出数组整体的特性,这也许是C标准的一个遗憾。

我一般只是将它作为一种特殊情况来解释:

1)sizeof(cA)

由于已将cA理解成常量指针,按理sizeof(cA)没有意义,但由于其和数组牵扯在一起不妨作为特例定义为cA整个数组的大小。

2) &cA

理由同1,按理指针的指针应该不是一回事,但这里作为特殊情况(还是数组名的缘故)将其另类地解释成指向数组整体的一个“指针”。


最后要强调的是,数组在C中(C++中也一样)并未被定义成一个“完全独立存在的完整类型”。这和char(*)[10]或char[10]形式无关,换言之没法将其定义成一个“有名份”的类型,所以指向此类数据结构的“指针”的功能是残缺的,甚至严格来说不能称其为指针。

使用特权

评论回复
22
hotpower| | 2008-5-16 13:02 | 只看该作者

哈哈~~~俺用&a没错过呀~~~

使用特权

评论回复
23
simon21ic| | 2008-5-16 13:17 | 只看该作者

ISO/IEC 9899:1999 (E):Page 46

3 Except when it is the operand of the sizeof operator or the unary & operator, or is a
  string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
  converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
  the array object and is not an lvalue. If the array object has register storage class, the
  behavior is undefined.
4 A function designator is an expression that has function type. Except when it is the
  operand of the sizeof operator54) or the unary & operator, a function designator with
  type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to
  function returning type’’.

使用特权

评论回复
24
dld2| | 2008-5-16 13:37 | 只看该作者

ding

使用特权

评论回复
25
hotpower| | 2008-5-16 13:41 | 只看该作者

讨论确实没意思~~~俺**&a是取变量a所在地址值别人随便去

使用特权

评论回复
26
dld2| | 2008-5-16 13:48 | 只看该作者

唉,C的典型问题

char *a;和char a[];的区别。

使用特权

评论回复
27
simon21ic| | 2008-5-16 13:51 | 只看该作者

实际使用中没有问题的话,就**自己认为正确的就可以了

这个问题也没有必要讨论下去了

PS:怎么加签名?

使用特权

评论回复
28
wxj1952| | 2008-5-17 11:51 | 只看该作者

只有一种规则!

只有一种规则!它实际上是以一种相当优雅的方式把我们这些完全不同的概念联系在一起。


《C与指针》P141:
    首先让我们学习一个概念,它被许多人认为是C语言设计的一个缺陷。但是,这个概念实际上是以一种相当优雅的方式把一些完全不同的概念联系在一起的。

考虑下面的声明:
  int a[5]; 
   a[1]的类型是整型,那a的类型又是什么?它所表示的又是什么?一个合乎逻辑的答案是它表示整个数组,但事实并非如此。
   
   在C中,在几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元素的地址。它的类型取决于数组元素的类型:如果它们是int类型,那么数组名就是“指向int的常量指针”;如果它们是其它类型,那么数组名的类型就是“指向‘其他类型’的常量指针”。
   数组具有一些和指针完全不同的特征。例如,数组具有确定数量的元素,而指针只是一个标量值。编译器用数组名来记住这些属性。只有数组名在表达式中使用时编译器才会为它产生一个指针常量。
   注意这个值是指针常量,而不是指针变量,你不能修改常量的值。你只要稍微回顾一下,就会认为这个限制是合理的:指针常量所指向的是内存中数组的起始位置。如果修改这个指针常量,唯一可行的操作就是把整个数组移动到内存的其他位置。但是,程序完成链接之后,内存中数组的位置是固定的。所以当程序运行时,再想移动数组就为时已晚了。因此,数组名的值是一个指针常量。

    只有在两种场合下,数组名并不用指针常量来表示:
1、当数组名作为sizeof操作符的操作数时:sizeof返回整个数组的长度,而不是指向数组的指针的长度。
2、当数组名作为单目操作符的操作数时:取一个数组名的地址所产生的是一个指向该数组的指针,而不是一个指向某个指针常量值的指针。

个人看法:既然说了“在C中......”那么现今所有的C都符合这个“相当优雅的”规则。如果是“有的C编译器这样,另一些编译器那样,......”那么这本世界流行的《C与指针》还不如我们这场讨论有价值?

使用特权

评论回复
29
hotpower| | 2008-5-17 16:04 | 只看该作者

c提倡指针反对数组,可delphi刚好相反~~~

俺喜欢C++和delphi,讨厌C,所以干什么都先想到"数组"或结构(类)~~~

例如俺这几天发了一帖水文:DSP5402之另类的"数组"访问
是dsp访问外部存储器的问题,它实际是访问的数组.

#define FLASH(x)  (*((volatile unsigned char *) 0x8000 + x))
/*----------------------------------------------------------
另类的"数组"访问,外扩的SST39VF800A从0x8000开始
void FlashObj::ChipErase(void)
{
  FLASH(0x5555) = 0xaa;  
  FLASH(0x2AAA) = 0x55;  
  FLASH(0x5555) = 0x80;
  FLASH(0x5555) = 0xaa;  
  FLASH(0x2AAA) = 0x55;  
  FLASH(0x5555) = 0x10;
  Wait(0x5555);
}
void FlashObj::Wait(unsigned int address)
{
unsigned int temp, val;
  do {
    val = FLASH(address);
    __nop();
    temp = FLASH(address);
    __nop();
  }
  while(((val ^ temp) & (1 << BIT6)) != 0);
}
----------------------------------------------------------*/


再有个真数组的水文: DSP281X变量地址数组定位方法

细心的人会看出来:

优秀的编译器对指针/数组/结构成员变量/结构指针的成员变量
等访问最终的优化代码几乎是相同的.

00说的:在keil51上 a==&a   

俺认为可能纯属巧合~~~

如果:
xdata unsigned i;

若此时i==&i俺真的再不玩51了~~~   

使用特权

评论回复
30
wxj1952| | 2008-5-17 18:08 | 只看该作者

圈圈说的是对的。

51C编译器在处理一个数组名/函数名时,首先从符号表中查询有没有这个名字:
1、如果有,那么它肯定也相应有固定的地址。这时将被编译为立即寻址或者直接寻址方式访问。如果用指针间接方式访问,那纯粹是“知易行难”。
2、如果符号表中没有这个名字(动态建立?)将采用指针间接寻址方式——指针用于访问无名地址。而数组和函数都是有名字的。
3、再举个例子:
int f(int);
int (*pf)(int)=f; // 本应写为...=&f;   这就像 pf=&f;/pf=f; 两者对编译器来说完全一样,“&”操作符只是显式地说明了编译器将隐式执行的任务。下面的3种函数调用方式,结果一样效率大不同。
f(55);        //立即寻址
(*pf)(55);  //间接寻址
pf(55);    //间接寻址

后两个式子编译代码完全一样。比第一个长N倍。


   

使用特权

评论回复
31
hotpower| | 2008-5-17 19:24 | 只看该作者

00要误导一大片了~~~

正如wxj1952所述,在编译器优化时,C默认了很多强制转换,很多在C++上是不允许的,因为这样很不安全,应该显式的转换.

拿数组来说,第1个数值的位置就是数组的物理位置即存储地址.结构也类同.

所以,A,&A,&A[0]都表示数组的首地址.

例如:
            &A[0]  &A[1]  &A[2]
A数组地址  0x1000,0x1002,0x1004

            A[0]   A[2]   A[2]
A数组数值  0x00,  0x01,  0x02

而对于一般变量来说
             &a
a变量的地址 0x2000
              a
a变量的数值  0x00


用c语言来表述:
unsigned int A[3] at 0x1000 = {0,1,2};
unsigned int a    at 0x2000 = 0;

若:
unsigned int *p;
   p = A;
   p = &A[0];
   p = A[0];肯定错  因为左值是指针变量p,应该是指针即地址
                    而右值是数组第1个单元A[0]的数值而非地址本身!
但是我的A[0]内就是我需要的地址呢???当然是要做强制转换了
即:
   p = (unsigned int *)A[0];

但是一般变量很容易误导.
   p = &a;//正确
   p = a;//我晕!!!a的地址&a是0x2000,而0x2000的内容a是0.

以下都能通过吗???

   p = (unsigned int *)0x2000;//知道a的地址

   if (p == &a)
   {
      puts("这个俺明白");
   }
   if (p == a)
   {
      puts("这个是做梦吧,除非编译器认为左值是指针右值肯定为指针即a的地址");
   }
   else
   {
      puts("俺**p != a的说明");
   }


故菜农认为:
即使编译器认为左值是指针,右值肯定为指针即地址.
那么也应该养成区分a和&a的好习惯~~~

否则程序移植到C++上就要漫天找错了~~~

使用特权

评论回复
32
simon21ic| | 2008-5-17 20:06 | 只看该作者

偶又忍不住了要说话了

to32楼:高级语言中定义的各种类型,在底层实现上都会失去其意义,所以底层代码处理数组,结构抑或是指针的方式是一样的
另外,C++和Delphi?应该是C++和Object Pascal吧。
偶稀饭Pascal的原因也包含hotpower所说的2点,1是可以不使用指针,减少出错的机会;2是强类型匹配。不过Delphi太贵,偶用Lazarus或者Turbo Delphi

偶看的书少,我对C的理解只是简单的按照规范文档的说明。
我写的代码也从来没有由于我理解不对而出问题,至于别人怎么理解就和我没有关系了,不过我是建议不要使用默认的类型转换

使用特权

评论回复
33
wxj1952| | 2008-5-17 20:35 | 只看该作者

旁观者清。

圈圈说的a是指楼主int a[5]={1,2,3,4,5};中的数组名,
而hot好像理解为了一般标量 xdata unsigned int a;

2个人说的两回事。
数组名/函数名不是标量,编译器将以一种优雅的方式特殊对待处理。
例如:
int *ptr=&a;  或者  int *ptr=a;  都是一样的。ptr都等于0x22(假定data地址。)
 printf(" %#x,%#x",a,ptr);  结果:0x22,0x22。

ptr=a; 左值ptr是地址,右值a是常量指针a的值(0x22)。概念上没问题。


使用特权

评论回复
34
hotpower| | 2008-5-17 22:19 | 只看该作者

一般数组取值为两种p=A;p=&A[0];估计没人p=&A;

使用特权

评论回复
35
simon21ic| | 2008-5-17 22:21 | 只看该作者

LS正解

所以讨论一个没人用的写法没意义啊

映像中途只有看到过一次&a的用法
#define sizeof(a)  ((char*)(&(a)+1) - (char*)&(a))

顺便提一下32楼的宏:
#define FLASH(x)  (*((volatile unsigned char *) 0x8000 + x))
最好写成
#define FLASH(x)  (*((volatile unsigned char *) 0x8000 + (x)))

使用特权

评论回复
36
hotpower| | 2008-5-18 07:13 | 只看该作者

这是俺在SPComm控件上将delphi倒塌的指针改造成string的源码

非常完美~~~

希望Delphi迷喜欢~~~


相关链接:http://blog.**/hotpower/11729/message.aspx

使用特权

评论回复
37
hotpower| | 2008-5-18 07:27 | 只看该作者

非常感谢simon21ic对宏bug的纠错!!!

哈哈~~~

当x为复杂的表达式时:

#define FLASH(x)  (*((volatile unsigned char *) 0x8000 + x))

中x的有部分可能与0x8000先"乱搞"~~~~

#define FLASH(x)  (*((volatile unsigned char *) 0x8000 + (x)))


俺以前就有过"惨痛"的教训~~~

开始:
#define LedChar0 LedSegA + LedSegB + LedSegC + LedSegD + LedSegE + LedSegF
//...................................

实战出错找了一天才想到了是宏bug~~~

以后俺都是:
#define LedChar0 (LedSegA + LedSegB + LedSegC + LedSegD + LedSegE + LedSegF          )
#define LedChar1 (          LedSegB + LedSegC                                        )
#define LedChar2 (LedSegA + LedSegB           + LedSegD + LedSegE           + LedSegG)
#define LedChar3 (LedSegA + LedSegB + LedSegC + LedSegD                     + LedSegG)
#define LedChar4 (          LedSegB + LedSegC                     + LedSegF + LedSegG)
#define LedChar5 (LedSegA           + LedSegC + LedSegD           + LedSegF + LedSegG)
#define LedChar6 (LedSegA           + LedSegC + LedSegD + LedSegE + LedSegF + LedSegG)
#define LedChar7 (LedSegA + LedSegB + LedSegC                                        )
#define LedChar8 (LedSegA + LedSegB + LedSegC + LedSegD + LedSegE + LedSegF + LedSegG)
#define LedChar9 (LedSegA + LedSegB + LedSegC + LedSegD           + LedSegF + LedSegG)
#define LedCharA (LedSegA + LedSegB + LedSegC           + LedSegE + LedSegF + LedSegG)
#define LedCharB (                    LedSegC + LedSegD + LedSegE + LedSegF + LedSegG)
#define LedCharC (LedSegA                     + LedSegD + LedSegE + LedSegF          )
#define LedCharD (          LedSegB + LedSegC + LedSegD + LedSegE           + LedSegG)
#define LedCharE (LedSegA                     + LedSegD + LedSegE + LedSegF + LedSegG)
#define LedCharF (LedSegA                               + LedSegE + LedSegF + LedSegG)


相关链接:https://bbs.21ic.com/club/bbs/ShowAnnounce.asp?id=2928997

使用特权

评论回复
38
hotpower| | 2008-5-18 07:48 | 只看该作者

从39楼给出的宏定义联想到:&a+1==a+1吗???

39楼给出的宏定义:
映像中途只有看到过一次&a的用法
#define sizeof(a)  ((char*)(&(a)+1) - (char*)&(a))

虽然俺不知是干什么的,但却联想到:

&a+1==a+1吗???

使用特权

评论回复
39
HWM| | 2008-5-18 08:00 | 只看该作者

这个问题早就有人相当透彻地分析过了

根本来说,由于C的历史所致,对C中数组名的“定义”是存在二义性的。好在存在一个自然的解决途径,就是“域外定义”。

正如我前面所述,对于一个指针而言谈论其尺寸大小是没有意义的,因此作为sizeof的定义拓广,令sizeof(cA)为cA数组的整体尺寸不会存在什么矛盾。另外由于cA是一个常量指针,取其地址也是没有意义的,同样作为定义拓广将&cA理解成一个指向数组整体的指针也未成不可。

一般情况下,二义性没啥不好,只要不出现歧义就行。在标准C++中,由于多重继承(VC未采用)就导致了二义性的出现。因为没法采取“域外定义”,为了避免歧义的出现,就加入了一系列的额外规定(如虚类等)。

但从另外的角度来看,作为一个好的习惯,尽量别去碰那些费脑浆的二义性。于人于己都没啥好处。

使用特权

评论回复
40
wxj1952| | 2008-5-18 15:30 | 只看该作者

37楼请用C编译器。

LZ的题是C程序,在所有最新C编译器下均编译通过。 37楼用C++编译器编译通不过,于是,以此为论据,用C编译器的人,都是概念不清。
    这讨论的是C数组与指针的概念,拿C++来做论据,以证明自己是对的,不太好吧。
   
   “取一个数组名的地址所产生的是一个指向该数组的指针,而不是一个指向某个指针常量值的指针。”

     Kenneth的这本经典著作是不是写错了?抑或C语言创造者比我们逊多了?

使用特权

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

本版积分规则