正确区分v o i d 与v o i d *

正确区分v o i d 与v o i d *
v o i d 及v o i d 指针类型对于许多C / C + + 语言初学者,甚至是部分有经验的程序员来说都
是一个谜,它让人云里雾里,不甚清晰,因此在使用时也会出现一些这样那样的问题。也许
在进入C / C + + 语言精彩世界的第一刻就认识了v o i d 和v o i d * ,可是它们的具体含义到底是什
么呢?
v o i d 是“无类型”,所以它不是一种数据类型;v o i d   * 则为“无类型指针”,即它是指向
无类型数据的指针,也就是说它可以指向任何类型的数据。
从来没有人会定义一个v o i d 变量,如果真的这么做了,编译器会在编译阶段清晰地提
示,“  i l l e g a l   u s e   o f   t y p e   ' v o i d ' ”。v o i d 体现的是“有与无”的问题,要先“有”了,在非v o i d
的前提下才能去讨论这个变量是什么类型的,此哲学思想渗透于小小v o i d 的使用与设计中。
v o i d 发挥的真正作用是限制程序的参数与函数返回值。在C / C + + 语言中,对v o i d 关键
字的使用做了如下规定:
(1 )如果函数没有返回值,那么应将其声明为v o i d 类型。
在C 语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。但是
许多程序员却误以为其为v o i d 类型。例如:
Add ( int a, int b );
int main()
{
   printf ( "1010 + 1001 = %d", Add ( 1010, 1001) );
   return 0;
}
Add ( int a, int b )
{
   return a + b;
}
程序运行的结果为:2   +   3   =   5 。这个结果更加明确地说明了函数返回值为i n t 类型,而非
v o i d 。
在林锐博士的《高质量程序设计指南—C + + / C 语言(第3 版)》一书中曾提到:“C + +
语言有很严格的类型安全检查,不允许上述情况(指函数不加类型声明)发生”。但是在一
些较老的编译器(比如V C + + 6 . 0 )中上述A d d 函数的编译无错也无警告且运行正确,所以不
能将严格的类型检查这样的重任完全交给编译器。
为了避免出现混乱,在编写C/C++ 程序时,必须对任何函数都指定其返回值类型。如果函
数没有返回值,则要声明为void。这既保证了程序良好的可读性,也满足了编程规范性的要求。
(2 )如果函数无参数,那么声明函数参数为v o i d 。
正如我们原先遇到的情况一样,如果在调用一个无参数函数时,一不小心为其设定了参数:
第1 章 从C 继承而来的   4 3
int TestFunction(void)
{
   return 2012;
}
int main()
{
   int thisYear = TestFunction(2011);
   // processing code
   return 0;
}
那么在C + + 编译器中编译代码时则会出错,提示“'   Te s t F u n c t i o n   '   :   f u n c t i o n   d o e s   n o t 
t a k e   1   p a r a m e t e r s ”。而在C 语言中,据说它能编译通过且能正确执行。之所以说是据说,是
因为本人没有在C 环境下实验证实这种情况,请原谅我的懒惰,因为我真的不想去碰Tu r b o 
C ,虽然那也曾经是我的入门开发环境。
所以,在C / C + + 中,若函数不接受任何参数,一定要指明参数为v o i d 。就算写的是C
函数,为了将来的兼容性,请不要省略这个v o i d 。

接下来说说特殊指针类型v o i d * 。
众所周知,如果存在两个类型相同的指针p I n t 1 和p I n t 2 ,那么我们可以直接在二者间互
相赋值;如果是两个指向不同数据类型的指针p I n t 和p F l o a t ,直接相互赋值则会编译出错,
必须使用强制转型运算符把赋值运算符右侧的指针类型转换为左侧的指针类型,这一点在建
议1 1 中已经解释得很清晰,代码如下所示:
int *pInt;
float *pFloat;
pInt = pFloat;  // 编译出错,提示“'=' : cannot convert from 'int *' to 'float *'”
pInt = (int *)pFloat; // 正确,需强制转型
而v o i d   * 则不同,任何类型的指针都可以直接赋值给它,无须强制转型,如下所示:
void *pVoid;
float *pFloat;
pVoid = pFloat;  // 正确,无需强制转型
但这种转换在C + + 中并不是双向的,在不使用强制转型的前提下,不允许将v o i d   * 赋
给其他类型的指针,如下所示:
void *pVoid;
float *pFloat;
pFloat = pVoid;  // 错误,编译失败,提示“'=' : cannot convert from 'void *' to ' float *'”
对于一般数据类型的指针,我们可以进行加减等算法操作,但是按照A N S I 标准,对
v o i d 指针进行算法操作是不合法的:
//  分别采用VC++ 编译器和Gcc 编译器进行验证
int * pInt;
pInt ++;     //  正确,pInt 指针增大sizeof(int)
pInt += 2;    //正确, pInt 指针增大2*sizeof(int)
void * pVoid;
pVoid ++;    //  错误,error C2036: "pVoid*": 未知的大小
pVoid += 1;    //  错误
A N S I 标准之所以这样认定,是因为只有在确定了指针指向数据类型的大小之后,才能
进行算法操作。但是大名鼎鼎的G N U 则有不同的规定,它指定v o i d   * 的算法操作与c h a r   *
一致。所以在上面代码片段中出现错误的代码在G N U 编译器中能顺利通过编译,并且能正
确执行。虽然G N U 较A N S I 更开放,提供了对更多语法的支持,但是A N S I 标准更加通用,
更加“标准”,所以在实际设计中,还是应该尽可能地迎合A N S I 标准。在实际的程序设计
中,为迎合A N S I 标准,并提高程序的可移植性,可以采用以下方式进行代码设计:
void * pVoid;
(char *)pVoid ++;    // ANSI:正确;GNU :正确
(char *)pVoid += 2;   // ANSI:错误;GNU :正确
如果函数的参数可以是任意类型指针,那么应声明其参数为v o i d   * ,最典型的例子就是
我们熟知的内存操作函数m e m c p y 和m e m s e t 的原型:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
仔细品味,就会发现这样的函数设计是多么富有学问,任何类型的指针都可以传入
m e m c p y 和m e m s e t 中,传出的则是一块没有具体数据类型规定的内存,这也真实地体现了
内存操作函数的意义。如果类型不是v o i d   * ,而是c h a r   * ,那么这样的m e m c p y 和m e m s e t 函
数就会与数据类型产生明显联系,纠缠不清,这不是一个通用的、“纯粹的、脱离低级趣味”
的函数设计!
请记住:
v o i d 与v o i d * 是一对极易混淆的双胞胎兄弟,但是它们在骨子里却存在着质的不同,区
分它们,按照一定的规则使用它们,可以提高程序的可读性、可移植性。仔细体会,还会发
现隐藏在它们背后的设计哲学。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. AccountsTester(账户测试) 1.1 Select Account Type(选择账户类型) 1.2 Get By Type(通过类型获得) 1.3 Get All(显示全部) 1.4 Add(增加用户) 1.4.1 可以简单的几个步骤配置一个交换用户(email地址和密码) 1.5 Properties(属性) 1.6 features(特征) 1.7 authtoken type(用户标志类型) 2.Bad Behavior(屏蔽垃圾发布器) 2.1 Crash the main app thread(破坏主要的应用程序线程) 2.2 Crash an auxiliary app thread(破坏一个辅助应用程序线程) 2.3 Crash the native process(破坏本地进程) 2.4 Crash the system server(破坏系统服务器) 2.5 Report a WTF condition(????) 2.6 ANR(Application Not Responding)(Stop responding for 20 seconds)——(应用无响应)(停止反应20s) 2.7 ANR starting an Activity(运行一个活动,但是应用无相应) 2.8 ANR recriving a broadcast Intent(接收一个广播意图,但是应用无响应) 2.9 ANR staring a Service(运行一个服务,但是应用无响应) 2.10 System ANR(in ActivityManager(系统无响应)(在行为控制器上) 2.11 Wedge system(5 minutes system ANR)(楔板系统)(5分钟系统无响应) 3.configuration(配置) configuration 3.1 fontScale=1.0(缩放比例=1.0) 3.2 hardKeyboardHidden=2(隐藏硬件键盘=2) 3.3 keyboard=2(键盘=2) 3.4 locale=en_US(现场环境=英文) 3.5 mcc=310(电机控制中心=310???)(MOTOR CONTROL CENTER) 3.6 mnc=260(位技术控=260)(Microcomputer Numberical Control) 3.7 navigation=3(导航=3) 3.8 navigationHidden=1(隐藏导航=1) 3.9 orientation=1(定位=1) 3.10 screenLayout=0x22(屏幕格式=0x22) 3.11 touchscreen=3(触摸屏=3) 3.12 uiMode=0x11(用户界面模式=0x11) DisplayMetrics(不显示的属性) 3.13 density=1.5(密度=1.5) 3.14 densityDpi=240(密度分辨率=240) 3.15 heightPixels=800(高度像素=800) 3.16 scaledDensity=1.5(尺度密度=1.5) 3.17 widthPixels=480(宽度分辨率=480) 3.18 xdpi=240.0(x轴分辨率=240.0) 3.19 ydpi=240.0(y轴分辨率=240.0) 4.Connectivity(连接工具) 4.1 Enable Wifi(启动Wifi) 4.2 Disable Wifi(关闭Wifi) 4.3 Start Wifi Toggle(启动Wifi开关) 4.4 Stop Wifi Toggle(关闭Wifi开关) 4.5 Wifi on(ms)(Wifi开启多长时间) 4.6 Wifi off(ms)(Wifi关闭多长时间) 4.7 Cycles done:1(周期做一次) 4.7.1 Start Screen Toggle(启动屏幕开关) 4.7.2 Stop Screen Toggle(关闭屏幕开关) 4.7.3 Wifi on(ms)(Wifi开启多长时间) 4.7.4 Wifi off(ms)(Wifi关闭多长时间) 4.8 Cycles done:0(周期做0次) 4.8.1 Start MMS(开启彩信) 4.8.2 Stop MMS(关闭彩信) 4.8.3 Start HiPri(开启导航) 4.8.4 Stop HiPri(关闭导航) 5.Development Settings(开发设置) 5.1 Debug App(调试程序) Android 键盘/Android 系统/API Domes/Certificate Installer(证书安装)/com.android.gestuer.builder()/com.android.sdksetup()/Custom Locale()/Dev Tools(开发工具)/Example Wallpapers(墙纸式样)/HTML查看器/Live Wallpaper Picker(动态壁纸选取)/NetSpeed(网速)/OpenWnn(一种输入法)/Pico TTS(语音程序)/Sample Soft Keyboard(样品软键盘)/sdk2.3/Spare Parts(备件)/Speech Recorder(演讲录音机)/Status Bar(状态栏)/Terminal Emulator(终端模拟器)/TTS Service(TTS服务)/User Dictionary(用户词典)/拨号器/拨号器存储/打包安装程序/发送电子邮件/谷歌拼音输入法/后备/计算器/联系人存储/浏览器/录音机/媒体存放/启动器/软件包访问帮助程序/设置/设置存储/时钟/受DRM保护的内容的存储/搜索/搜索应用程序提供商/通讯录/下载管理器/下载内容/相机/信息/虚拟专用网服务/音乐/账户与同步设置/住屏幕提示 5.2 Wait for debugger(等待调试程序) 5.3 pointer location(触点位置) 5.4 show running processes(显示运行的程序) 5.5 show screen updates(显示屏幕更新) 5.6 Disable compatibility mode(禁用兼容性模式) 5.7 app process limit(应用程序限制) 5.8 immediately destroy activities(立即毁坏项目) 5.9 show cpu usage(显示CPU的进程) 5.10 show sleep state on LED(再LED上显示睡眠时间) 5.11 window animation scale 1x(窗口动画规模1X) 5.12 transition animation scale 1x(转换动画模式1X) 5.13 Light Hinting(轻显示) 5.14 show gtalk service connetion status(显示即时通讯连接标志) 6.goole login service(谷歌登录服务) 7.Instrumentation(仪表) 7.1 local sample(本地例子) 8. Media Scanner(媒体扫描仪) 9. Package Browser(包浏览器) 目录参照5.1 例如:Android键盘 Package Summary(包装总结) a. com.android.inputmethod.latin(来源网站) d. Restart(重启) b. (No Application Class)(无应用类型) c. (NO Label)(无标签) e. system(系统) f. process(程序) com.android.inputmethod.latin g. User ID(用户帐号) 10016 h. Task Affinity(任务类同) "com.android.inputmethod.latin" i. Version(版本) 2.3.1(#9) j. Source(资源) /system/app/LatinIME.apk k. Data(数据) /data/data/com.android.inputmethod.latin l. Activities(活动) LatinIMESettings/LatinIMEDebugSettings/InputLanguageSelection 例如:LatinIMESettings“android键盘设置” Multiple(normal):倍数(正常的) Process(程序) com.android.inputmethod.latin Task Affinity(任务类同) com.android.inputmethod.latin Required Permission(许可要求) (none) Multiprocess(多处理器) No Clear on Background(在背景中清理) No State Not Needed(国家不需要) No m. Services(服务) LatinIME(android键盘) 10. Pointer Location(触点的坐标位置) P:0(左键松开)/0(没有触点屏幕);X和Y(复位值):绝对值的dx为横向的绝对长度,正号代表从左向右触摸,负号正好相反。dy的绝对值代表纵向的绝对长度,正号代表从上往下触摸,负号正好相反;Xv和Yv:表示红线的横向和纵向相对长度,正负号的意思和X和Y一样;Prs:是否有点击屏幕;Size:线的尺寸(只显示一种) 11.Running processes(正在运行的程序) 例如:system process Information(程序信息) Process Name:(程序的名字) system(系统) package in process:(在程序中的包文件) android com.android.providers.settings 12. Sync Tester(同步测试) 12.1 Registered Sync Adapters:(注册同步适配器) 12.2 选择网站 12.3 bind(捆绑):点击显示:a.已经连接到同步适配器.b.连接资源地址:。。。c.账户类型:。。。 unbind(不捆绑);start sync(开始同步) cancel sync(取消同步)。 13. Terminal Emulator(终端模拟器)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值