为什么写这篇文章呢? 为什么要弄这么个题目呢?

  首先解释为什么用这个题目。这一切都要从那天在QQ群中的讨论说起,那天在群中,一个哥们问了一个关于(void)0 的问题。然后大家说到了

(void)0和(void*)0; 大家看看(void)0 和(void*)0 ,是不是一个像个平胸的小妹,一个像个丰韵的美女。

  他问的的问题如下:

(void);  //这个语句在C语句中可以执行吗?  

  我想了一下这个语句应该没有什么问题,在没有用(void)0,去影响内存对象的情况下,应该是可以的。下面是我在FC 14中进行测试的结果。

[volcanol@volcanol c]$ ls
a.out test.c
[volcanol@volcanol c]$ cat test.c
#include <stdio.h> int main(int argc,char** argv)
{
int test; test=; (void); getchar(); return ;
} [volcanol@volcanol c]$ gcc -Wall test.c
[volcanol@volcanol c]$

  可以发现,编译过程没有警告和错误信息。

然后,我们就讨论是否可以将(void)0 赋值给其他的对象,于是我就修改了一下,将其改成赋值。

[volcanol@volcanol c]$ cat -n test.c
#include <stdio.h> int main(int argc,char** argv)
{
int test; test=(void); getchar(); return ;
}

编译输出信息:

[volcanol@volcanol c]$ gcc -Wall test.c
test.c: 在函数‘main’中:
test.c::: 错误:void 值未如预期地被忽略

可以看出,void类型不能通过隐式类型转换为int类型。

既然我们不能将void类型的值赋值,那么定义void类型的变量呢?

[volcanol@volcanol c]$ cat -n test.c
#include <stdio.h> int main(int argc,char** argv)
{
void test; test=(void); getchar(); return ;
}

编译器输出信息如下所示:

[volcanol@volcanol c]$ gcc -Wall test.c
test.c: 在函数‘main’中:
test.c::: 错误:变量或字段‘test’声明为 void
test.c::: 错误:void 值未如预期地被忽略

可以发现,不能将变量定义为void类型。

  下面我们来讨论一下整个过程。

1、void类型

void表示为无类型,在 K&R C 里面有明确的说明。

因为不能在Linux下上传图片,所以就不上传图片里,可以到 K&R 第二版的 附录 A.6.7 查看相关的内容。

K&R C里面明确的指出: void类型对象的值不能以任何方式使用,也不能显式或者隐式的转换为非空类型。void类型表示

一个不存在的值,任何对象转换为void类型都将返回一个不存在的值,因此也就不能将void转换为其他非空类型。

2、void类型的作用

【1】声明函数不需要返回任何值

这个需要注意下面两个函数定义的差别:

getx();   //函数1

void getx(); //函数2

注意:函数1和函数2是两个不一样的函数。

【2】声明函数不需要传递任何

getx();  //函数1

getx(void); //函数2

注意:函数1和函数2 一样。

【3】返回void对象的表达式语句,作用和空语句一样。

(void)x; // 空对象表达式语句

;  //空语句

在编译的时候,编译优化后,这两个语句都不产生任何实际代码。

3、void* 类型

指向任何对象的指针都可以转换为void* 类型,而且在转换过程中不会丢失信息;一个被转换为void* 类型的指针可以转换为初始类型,

并且在转换的过程中不会丢失信息。

char *p="Hello world";

char *pVoid = (void*)p;

  下面是我的测试代码:

[volcanol@volcanol c]$ cat -n test.c
#include <stdio.h> int main(int argc,char** argv)
{
char *p="Hello world"; char* pVoid=(void*)p; puts(pVoid); getchar(); return ;
} [volcanol@volcanol c]$ gcc -Wall test.c
[volcanol@volcanol c]$ ./a.out
Hello world

可以看到,这样的结果符合原本的定义。  分析代码中的第7行语句, 首先将p指针显式的转换为(void*);  然后再将空类型指针(void*)p隐式的转换为char*, 可以看到

这个过程没有丢失信息。

这里我们可以看到: 挺拔的void*可以任意的和别人交往,而平胸的void成了嫁不出去的姑娘。

4、关于void* 变量和常量

在C语言库中,预定义了一个常量:NULL; 通常是如下定义的:

#define  NULL  ((void*)0)

这个常量可以赋值给任意类型的指针。例如:

char* p=NULL;

这个语句在编译时不会出错,当然如果程序中不再对p进行再赋值,这个指针p通常也不能进行操作,例如此时不能用于puts(p);

这里还需要说一个特别的事情,就是关于0这个常量在C 语言中的应用,这个在获取结构体变量的成员offset地址非常有用。

[volcanol@volcanol c]$ cat -n test.c
#include <stdio.h> struct testType
{
int x;
char y;
struct testType *z;
}; int main(int argc,char** argv)
{ int x=((size_t)&((struct testType*))->y); printf("%d",x); getchar(); return ;
} [volcanol@volcanol c]$ gcc -Wall test.c
[volcanol@volcanol c]$ ./a.out

这里内存地址0,可以引用为任意指针类型,这个内存地址是不允许应用程序引用的,这也就是如果将一个指针赋值为NULL后不能引用的原因。

关于void* 变量,在网络上盛传一篇文章: http://wenku.baidu.com/view/22c4b8d86f1aff00bed51edc.html,

这篇文章中对void* 指针某些描述,实际上是用某个平台的某个编译的特殊情况来描述的,存在一些偏颇之处,例如文章中说

   但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。道理很简单,
我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。下面的语句编译出错:

而且和多人还对里面的说法深信不疑, http://www.cnblogs.com/ComputerG/archive/2012/02/22/2363165.html

下面的这个链接对void* 指针的描述比较详细:  http://learn.akae.cn/media/ch23s01.html

我们可以看下面的代码和执行情况:

[volcanol@volcanol c]$ cat -n test.c
#include <stdio.h> int main(int argc,char** argv)
{
char *p="Hello world"; void* pVoid=(void*)p; puts(pVoid); getchar(); return ;
} [volcanol@volcanol c]$ gcc -Wall test.c
[volcanol@volcanol c]$ ./a.out
Hello world

实际上: void* 指针也是一个指针,具有普通指针的某些特性,例如  sizeof(void *)具有和sizeof(char *)一样的大小,也就是说,void* 变量同样占用4个字节(32位系统),这个

内存位置,同样可以存储一个内存地址。而设置void*的一个目的就是无需进行显式地址转换就可以将void* 指针转换为其他任意指针, 因为最初的时候,是用char* 做这个功能的。

这样每一次进行转换的时候,都必须将char* 指针进行强制类型转换。

这个地方,就不再细说了,在C语言中,(void)0注定有平胸姑娘的尴尬,成了嫁不出去的姑娘。

文章的内容,均为一孔之见,如果有不同意见,欢迎拍砖。 另外,前两次有朋友说要我的电子书,这里我不太方便上传,如果您需要电子书,可以加我QQ,我的QQ在博客园

中的个人信息里面添了,加的时候请说明是要电子书的,我会根据您的需要给你传,要我上传,我的书太多(达50G之多,很多种类的,不只是计算机的,有需要的都可以索要)。

【C语言学习趣事】_32_平胸的尴尬,嫁不出去的姑娘的更多相关文章

  1. 【C语言学习趣事】_33_关于C语言和C++语言中的取余数(求模)的计算_有符号和无符号数的相互转换问题

    最近再次复习C++语言,用的教材是<C++ Primer>这本教材, 看到第二章的时候,里面有个问题困扰了我. 于是想上网查查怎么回事, 结果看了很久都没有得到一个满意的答案. 书上有这么 ...

  2. GO语言学习(二)Windows 平台下 LiteIDE 的安装和使用

    1. 安装 Go 语言并设置环境变量 参考GO语言学习(一) 2. MinGW 的下载和安装 Windows 下的 Go 调试还需要安装 MinGW. 2.1 下载安装工具的安装 最新版本下载安装工具 ...

  3. 20165316 技能学习心得与c语言学习

    20165316 技能学习心得与c语言学习 一.技能学习经验 我会打乒乓球,在中国,我只能说我"会"打,至于"比大多数人更好"我不敢断言,因为我无时无刻不感受到 ...

  4. C语言学习 第八次作业总结

    本次作业其实没有新的内容,主要就是复习上一次的一维数组的相关内容.冯老师布置了5道题目,其中涉及到一些比较简单的排序或者是查找的方法.因为数据很少,所以直接使用for循环遍历就可以了. 关于本次作业, ...

  5. C语言学习 第七次作业总结

    C语言学习 第七次作业总结 数组可以分为数组和多下标数组(在传统的国内C语言书本中,将其称为二/多维数组). 数组名称 在之前的课程中,大家应该都有印象,对于int a这样的定义,会为变量 a 声明一 ...

  6. 技能收获与C语言学习

    你有什么技能比大多人(超过90%以上)更好? 我会的东西很多,喜欢的东西太多,但是很遗憾广而不专,会而不精.学了很多东西我都是为了娱乐,因为以前我们那里过于强调学习,很多爱好也都被扼杀在摇篮里.我觉得 ...

  7. 一份关于Swift语言学习资源的整理文件

    一份关于Swift语言学习资源的整理文件     周银辉 在这里下载 https://github.com/ipader/SwiftGuide

  8. go语言学习笔记

    Go语言学习基本类型Bool 取值范围:true,false (不可以用数字代替)Int/uint 根据平台可能为32或64位int8/uint8 长度:1字节 取值范围-128~127/0~255b ...

  9. 20155206赵飞技能获取经验,C语言学习感想与对JAVA的学习目标

    自己较强的技能获取经验. 1:实话实说我自己是没有哪个技能可以超过90%的人的,只有自认为做的还可以的一些事情,例如打篮球,office软件的应用,一百米跑.至于其他方面就是很平庸了. 2:经验主要有 ...

随机推荐

  1. MVVM架构~Knockoutjs系列之js接收C#数据集合的方式

    返回目录 在controller里将数据拿到,并且存储到ViewBag对象里,最后在View上显示出来,这是传统的MVC开发方式,事实上引入Knockoutjs以后,这种方式还是适合的,Knockou ...

  2. Atitit 基于图片图像 与文档混合文件夹的分类

    Atitit 基于图片图像 与文档混合文件夹的分类 太小的文档(txt doc csv exl ppt pptx)单独分类 Mov10KminiDoc 但是可能会有一些书法图片迁移,因为他们很微小,需 ...

  3. 让BI告诉你:圣诞老人去哪了?

    刚看到一篇关于圣诞节BI分析的文章,觉得很有意思,特来翻译了下和大家一起分享(可惜的是文章发布的时间有点久). 伴随着圣诞节即将到来的日子,POWER BI团队来回答大家最为关注的一个问题:圣诞老人到 ...

  4. 【WP开发】手电筒

    或许很多人都想到,可以利用手机上摄像头的闪光灯做手电筒,当然,有利必有害,每次使用的时间不要过长,几分钟一般不会有什么问题,如果时间太长,难保会有损伤. 以往的方案是调用视频录制功能来开始录制视频,同 ...

  5. java错误

    Workspace in use or cannot be created, choose a different one. 出现这种情况一般是workspace的配置文件中出现了.lock文件(wo ...

  6. ZOJ 3804 YY's Minions (简单模拟)

    /* 题意:一个矩阵中有 n*m个宠物,每一个宠物都有一个状态, 1醒着的,0睡着的 X离开的!如果这个宠物(醒着的)的周围醒着的个数>3 || <2它就会睡着, 如果这个宠物(睡着的)的 ...

  7. PHP的学习--Traits新特性

    在阅读yii2源码的时候接触到了trait,就学习了一下,写下博客记录一下. 自 PHP 5.4.0 起,PHP 实现了代码复用的一个方法,称为 traits. Traits 是一种为类似 PHP 的 ...

  8. c++ ofstream & ifstream文件流操作

    ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间; //ofstream & ifstream inherit from istream class ...

  9. Lagrange插值公式

    朋友@耗子突然问起我一个 Lagrange 插值公式的问题,发现几年没碰差不多要忘干净了,于是找了本教科书来翻了翻,顺便把几个要点整理成文,以备日后查阅. 作者: peghoty 出处: http:/ ...

  10. Pentaho Kettle 6.1连接CDH5.4.0集群

    作者:Syn良子 出处:http://www.cnblogs.com/cssdongl 欢迎转载 最近把之前写的Hadoop MapReduce程序又总结了下,发现很多逻辑基本都是大致相同的,于是想到 ...