C语言结构体声明

这两个声明有什么不同?
 struct x1{};
 typedef struct {}x2;

 第一种形式声明了一个“结构标签”;第二种声明了一个“类型定义”。主要的区别在于第二种声明更显抽象一些---用户不必知道他是一个结构,且声明他的实例时也不需要使用关键字typedef
 x2 b;
 但是使用标签的结构就必须用这样的形式进行定义。
 struct x1 a;
 同时也可以使用这两种方法:
 typedef struct x3{}x3;尽管有些晦涩,但为标签和类型定义使用同样的名称是合法的,因为他们处于独立的命名空间中。

这样的代码有什么不对?
 struct x{};
 x thestruct;

c不是c++。不能用标签自动生成类型定义名,事实上,c语言中的结构是这样用关键字struct 声明的:
 typedef struct {} tx;
 tx  thestruct;
 如果你愿意,也可以在声明结构的时候声明一个类型定义,然后再用这个类型定义名称去声明真正的结构:
 typedef struct {}tx;
 tx thestruct;

 c语言中用什么方法实现抽象数据类型最好?
 
 让客户使用指向没用公开定义的结构类型的指针是一个好办法。换言之,客户使用结构指针(及调用输入和返回结构指针的函数)而不知道结构的成员是什么。只要不需要结构的细节--也就是说。只要不使用->,sizeof,操作符及真是结构的声明--c语言事实上可以正确处理不完全类型的结构指针。只有在实现抽象数据类型的源文件中才需要此范围内的结构的完整声明。

c语言中是否有模拟继承等面向对象程序设计特性的好方法?
 把函数指针直接加入到结构中就可以实现简单的“方法”,你可以使用各种不雅而暴力的方法来实现继承,例如通过预处理器或让“基类”的结构作为初始的子集,但这些方法都不完美,很明显,也没有操作符的重载和覆盖,那些必须人工去做。
 显然,如果你需要“真”的面向对象程序设计,则需要使用一个支持这些特性的语言。


  这样的声明结构的代码:
  struct name{
 int namelen;
 char namestr[1]; 
}
然后有使用一些内存分配技巧使namestr数组用起来好像有多个元素,namelen记录了元素个数,他是怎样工作的?这样是合法的和可移植的吗?

不清楚是这样是否合法或可移植,但是这种技术十分普遍,这种技术的某种实现可能像这个样子:
  #include
  #include
 
  struct name *makename(char *newname)
{
 struct name *ret=malloc(ziseof(struct name)-1+strlen(newname)+1);//-1 for initial[1];+1 for \0;
  if(ret!=NULL)
 {
 ret->namelen=strlen(newname);
  strcpy(ret->namestr,newname);
 }
return ret;
}

这个函数分配了一个name结构的实例并调整他的大小。以便将请求的名称(不是结构声明所示的仅仅一个字符)置入namestr域中。
 虽然很流行,但这种技术也在某种程度上惹人非议。Dennis Ritchie就称之为“和c实现的无保证的亲密接触”。官方的解释认定它没有严格遵守c语言标准。这种技术也不能保证在所有的实现上是可移植的。

 另一种可能是把变长的元素声明成很大,而不是很小,上面的例子可以这样改写:

  #include
  #include
  #define MAX 100
 
  struct name{
 int namelen;
 char namestr[MAX]; 
}
  struct name *makename(char *newname)
{
 struct name *ret=malloc(ziseof(struct name)-MAX+strlen(newname)+1);//+1 for \0;
  if(ret!=NULL)
 {
 ret->namelen=strlen(newname);
  strcpy(ret->namestr,newname);
 }
return ret;
}

当然,此处的MAX应该比任何可能存储的名字长度都大,但是,这种技术似乎不完全符合标准的严格解释.
  当然,真正安全的正确做法是使用字符指针,而不知数组。
  #include
  #include
    struct name{
 int namelen;
 char *namep; 
}

  struct name *makename(char *newname)
{
 struct name *ret=malloc(ziseof(struct name));
  if(ret!=NULL)
 {
 ret->namelen=strlen(newname);
 ret->namep=malloc(ret->namelen+1);
 if(ret->namep==NULL)
 {
   free(ret);
 return NULL;
 }
  strcpy(ret->namestr,newname);
 }
return ret;
}
显然,把长度和字符串保存在同一内存中的“方便”已经不复存在了,而且在释放这个结构的实例的时候需要两次调用free。
    如果像上面的例子那样,存储的数据类型是字符,那么为保持持续性,可以直截了当将两次malloc调用合成一次(这样也可以只用一次调用free就能释放)
     struct name* makename(char * newname)
{
   char * buf=malloc(sizeof(struct name)+strlen(newname)+1);
   struct name *ret=(struct name *)buf;
   ret->namelen=strlen(newname);
   ret->namep=buf+sizeof(struct name);
   strcpy(ret->namep,newname);
   return ret;
}

但是,像这样用一次malloc调用将第二个区域接上的技巧只有在第二个区域是char型数组的时候才可移植。对于任何大一些的类型,对齐变得十分重要,必须保持。
  这些“亲密”结构都必须小心使用,因为只有程序员知道它的大小,而编译器却一无所知。

为什么不能用内建的==和!=操作符比较结构?
 没有一个好的,符合c语言的底层特性的方法让编译器来实现结构比较,简单的按字节比较的方法可能会在遇到结构中没有使用的“洞”的随机内容时候失败(这些事补位用来保证后续的成员正确对齐的),而按域比较在处理大结构时可能需要难以接受的大量重复代码,任何编译器生成的比较代码都不能在所有情况下都能正确比较指针域,例如,比较char* 域的时候都希望使用strcmp而不是==,如果需要比较两个结构,必须自己写函数。

  结构传递和返回时如何实现的?
  挡结构作为函数参数传递时,通常会把整个结构都推进栈,需要多少空间就是用多少空间(为了避免这个代价程序员经常使用指针而不是结构)某些编译器仅仅传递一个结构的指针,但是为了保证按值传递的语义,它们可能不得不保留一份局部副本。
  编译器通常会提供一个额外的“隐藏”参数,用于指向函数返回的结构,有些老式的编译器使用一个特殊的静态位置来返回结构,这回导致结构的函数不可栽入,这是ANSI c所不允许的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值