将0转型为“指向返回值为void的函数的指针” (void (x)())0
c语言中void的用法
c语言中void的用法c语言中void的用法的用法你知道吗?下面就跟你们详细介绍下c语言中void的用法的用法,希望对你们有用。
c语言中void的用法的用法如下:void指针是什么?void指针一般被称为通用指针或泛指针,它是C关于“纯粹地址(raw address)”的一种约定。
void指针指向某个对象,但该对象不属于任何类型。
请看下例:int*ip;void*p;在上例中,ip指向一个整型值,而p指向的对象不属于任何类型。
在C中,任何时候你都可以用其它类型的指针来代替void指针(在C++中同样可以),或者用void指针来代替其它类型的指针(在C++中需要进行强制转换),并且不需要进行强制转换。
例如,你可以把char *类型的指针传递给需要void指针的函数。
什么时候使用void指针?当进行纯粹的内存操作时,或者传递一个指向未定类型的指针时,可以使用void指针。
void指针也常常用作函数指针。
有些C代码只进行纯粹的内存操作。
在较早版本的C中,这一点是通过字符指针(char *)实现的,但是这容易产生混淆,因为人们不容易判断一个字符指针究竟是指向一个字符串,还是指向一个字符数组,或者仅仅是指向内存中的某个地址。
例如,strcpy()函数将一个字符串拷贝到另一个字符串中,strncpy()函数将一个字符串中的部分内容拷贝到另一个字符串中:char *strepy(char'strl,const char *str2);char *strncpy(char *strl,const char *str2,size_t n);memcpy()函数将内存中的数据从一个位置拷贝到另一个位置:void *memcpy(void *addrl,void *addr2,size_t n);memcpy()函数使用了void指针,以说明该函数只进行纯粹的内存拷贝,包括NULL字符(零字节)在内的任何内容都将被拷贝。
c语言中返回指针的函数
c语言中返回指针的函数C语言中可以编写返回指针的函数。
这种函数的返回类型是指针类型,它返回一个指向特定类型的内存地址的指针。
通过返回指针,我们可以在函数之外访问和操作函数内部创建的变量或数据结构。
返回指针的函数在很多情况下非常有用,例如动态内存分配、数据结构的创建和操作等。
下面我将从几个角度介绍返回指针的函数的使用。
1. 动态内存分配,返回指针的函数可以用于动态分配内存。
例如,C语言中的`malloc()`函数就返回一个指向分配内存的指针。
我们可以编写类似的函数,根据特定的需求动态分配内存,并返回指向该内存的指针。
这样可以有效地管理内存,并在需要时释放内存。
2. 数据结构的创建和操作,返回指针的函数可以用于创建和操作复杂的数据结构,如链表、树等。
通过返回指向数据结构的指针,我们可以在函数之外对其进行访问和修改。
例如,可以编写一个函数来创建链表节点,并返回指向该节点的指针。
这样可以方便地在链表中插入、删除和修改节点。
3. 减少内存拷贝,返回指针的函数可以避免不必要的内存拷贝。
如果函数返回一个大型的结构体或数组,将其作为返回值进行拷贝可能会导致性能下降。
而返回指向结构体或数组的指针,可以减少内存拷贝的开销,提高程序的效率。
4. 共享数据,返回指针的函数可以用于共享数据。
通过返回指向某个全局变量或静态变量的指针,多个函数可以访问和修改同一份数据。
这在多线程编程或需要在不同函数之间传递数据时非常有用。
需要注意的是,在使用返回指针的函数时,我们需要确保返回的指针指向的内存是有效的,并且在需要时负责释放该内存,以避免内存泄漏。
总结起来,返回指针的函数在C语言中是一种非常有用的编程技巧。
它可以用于动态内存分配、数据结构的创建和操作、减少内存拷贝以及共享数据等方面。
合理使用返回指针的函数可以提高程序的效率和灵活性。
C++对象指针转换
在C++中存在两种转换:隐式转换和显式转换(强制转换)。
一、隐式类型转换C++定义了一组内置类型对象之间的标准转换,在必要时它们被编译器隐式地应用到对象上。
隐式类型转换发生在下列这些典型的情况下;1、在混合类型的算术表达式中。
在这种情况下,最宽的数据类型成为目标转换类型。
这也被称为算术转换arithmetic conversion 例如:int ival = 3;double dval = 3.14159;// ival 被提升为double 类型: 3.0 (是一种保值转换)ival + dval;2、用一种类型的表达式赋值给另一种类型的对象。
在这种情况下,目标转换类型是被赋值对象的类型。
例如,在下面第一个赋值中文字常量0 的类型是int 它被转换成int*型的指针表示空地址在第二个赋值中double 型的值被截取成int 型的值。
// 0 被转换成int*类型的空指针值int *pi = 0;// dval 被截取为int值3 (这不是保值转换),一般情况下编译器会给出warning.ival = dval;3、把一个表达式传递给一个函数调用,表达式的类型与形式参数的类型不相同。
在这种情况下,目标转换类型是形式参数的类型。
例如:extern double sqrt( double );// 2 被提升为double 类型: 2.0cout4、从一个函数返回一个表达式,表达式的类型与返回类型不相同。
在这种情况下,目标转换类型是函数的返回类型。
例如:double difference( int ival1, int ival2 ){// 返回值被提升为double 类型return ival1 - ival2;}二、显示转换(强制转换)(一)、旧式强制类型转换:由static_cast,cons_cast 或reinterpret_cast 强制转换符号语法,有时被称为新式强制转换符号,它是由标准C++引入的。
c++知识题库(25题)
1. 以下哪个选项是C++中的基本数据类型?A. classB. structC. intD. namespace2. 在C++中,下面哪个运算符用于指针的解引用?A. &B. *C. ->D. ::3. 在C++中,下面哪个关键字用于定义常量?A. constantB. defineC. constD. static4. 以下哪个选项不是C++中的访问控制符?A. publicB. privateC. protectedD. secured5. 在C++中,以下哪个函数用于获取当前对象的指针?A. getPointer()B. thisPointer()C. currentObject()D. this6. 在C++中,虚函数用于实现什么特性?A. 封装B. 继承C. 多态D. 重载7. 在C++中,以下哪个容器属于STL中的顺序容器?A. mapB. setC. vectorD. unordered_map8. 以下哪个选项是C++中的流操作符?A. <<B. >>C. <>D. 以上都对9. 在C++中,以下哪个选项不是标准模板库(STL)中的算法?B. findC. insertD. copy10. 在C++中,析构函数的名称前面应加哪个符号?A. ~B. &C. *D. #判断题11. 在C++中,构造函数可以是虚函数。
(对/错)12. C++中允许函数重载。
(对/错)13. C++中类的静态成员变量在类的每个对象中都有一份副本。
(对/错)14. 在C++中,所有的操作符都可以重载。
(对/错)15. 在C++中,new运算符和malloc函数都是用来动态分配内存的,但它们的返回类型不同。
(对/错)填空题16. 在C++中,函数的返回类型为void表示该函数______。
17. 在C++中,使用关键字______可以防止一个类被继承。
c语言中的void用法详解
在C语言中,void是一个关键字,用于表示无类型或无返回值。
以下是void在C 语言中的主要用法详解:
1. 函数返回类型:
void通常用作函数的返回类型,表示该函数不返回任何值。
例如:
在上面的例子中,printHello函数没有返回值,因此返回类型是void。
2. 指针类型:
void指针是一种特殊类型的指针,可以指向任何类型的数据。
这在一些情况下是很有用的,例如在动态内存分配和函数参数传递时。
示例:
在上述例子中,genericPointer是一个void指针,可以指向不同类型的数据。
3. 函数参数类型:
void可以用作函数的参数类型,表示该函数不接受任何参数。
例如:
在这个例子中,doSomething函数不接受任何参数。
4. 空指针:
void可以用作表示空指针的类型。
例如:
这里,nullPointer是一个void指针,被初始化为NULL,表示它不指向任何有效的内
存地址。
5. 函数指针:
void也可以用作函数指针的返回类型,表示该函数指针不关心返回值的类型。
例如:
在上面的例子中,functionPointer是一个接受两个整数参数的函数指针,它指向一个
返回类型为void的函数add。
总体而言,void在C语言中的用法涵盖了函数、指针、参数等多个方面,用于表示无类型、无返回值或通用类型。
C和C++语言中的void及void指针总结
C/C++语言中的void及void指针总结一、void 和void* 含义void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
对于void,如果定义void a;是会编译出错的(vc6下得到:error C2182: 'a' : illegal use of type 'void',vs08中:error C2182: “a”: 非法使用“void”类型)对于void*,任何类型的指针都可以直接赋值给它,无需进行强制类型转换。
1.void *p1;2.int *p2;3.p1 = p2;这样是正确的,不过不能将int*转换为void*二、我们在什么地方能用到void和void*1、对于void,发挥作用的有两个地方:一是对函数返回值的限定,二是对函数参数的限定。
下面举例说明:(林锐的《高质量c++编程指南》上有以下3个对void和void*的使用的类似示范,即,如没有参数,一定要写明void;如没有返回值,一定标注;如果函数参数可以为任意类型指针,声明函数参数为void*)1)对于返回值的限定1.#include "stdio.h"2.add ( int a, int b )3.{4.return a + b;5.}6.int main(int argc, char* argv[])7.{8. printf ( "2 + 3 = %d \n ", add ( 2, 3) );9.return 0;10.}上述程序,在C语言中运行是没有任何问题的,因为c语言中,函数如果没有返回值限定,则编译器默认返回为int来处理。
虽然看起来会以为返回void。
但是在c++中,类似代码:1.#include <iostream>ing namespace std;3.add ( int a, int b )4.{5.return a + b;6.}7.int main(int argc, char* argv[])8.{9. cout << "2 + 3 = "<< add ( 2, 3) << endl;10.return 0;11.}在vc6中编译依旧没有问题的,但是在vs08中测试,会得到错误:error C4430: 缺少类型说明符- 假定为int;在gcc下编译会出错:error: ISO C++ forbids declaration of 'add' with no type。
C++经典面试题(2012年校园招聘)
1、在C++程序中调用被C编译器编译后的函数,为什么要加extern "C"?答案:C语言不支持函数重载,C++ 提供了C连接交换制定符号extern "C"解决名字匹配问题。
2、如何判断一段程序是由C编译程序还是由C++编译程序编译的?答案:C++编译时定义了_cplusplus。
C编译时定义了_STDC_。
3、main主函数执行完毕后,是否可能会再执行一段代码?给出说明。
答案:如果需要加入一段在main退出后执行的代码,可以使用atexit()函数注册一个函数,代码为:int atexit(void (*funciton)(void));4、用预处理指令#define声明一个常数,用以表明一年中有多少秒(忽略闰年问题)。
答案:#define SECONDS_PER_YEAR (60*60*24*365)UL 注意括号,同时不能用分号,不要写出计算出来的实际值,用到无符号长整型。
5、const与#define有什么区别?答案:两者都可以定义常量。
1)const常量有数据类型,而宏常量没有数据类型。
编译器可以对前者进行安全检查,而对后者只进行字符替换,没有类型安全检查;2)有些集成化调试工具可以对const进行调试,不能对宏常量进行调试。
const在C中其实是值不能修改的变量,因此会给它分配存储空间(默认是外部连接的),在C++中对于基本数据类型的常量,编译器会把它放到符号表里而不是分配存储空间(默认是内部连接的,若强制声明为extern,则需要分配存储空间)。
const int bufsize = 100; //在C++中注意此处int一定不可少,因为c++中不支持默认int型char buf[bufsize]; //在C++中这样写没问题const bufsize;//在C中这样写没问题,但是在C++中是有错误的。
//要做同样的事情,C++需改强制声明为extern:extern const bufsize;6、写一个标准宏MIN,输入两个参数返回最小值。
函数指针void (fun)() 解析等
fun(); // 或 (*fun)();
fp2(1); // 或 (*fun)(1);
void (*fun)(void *);定义一个指针,该指针指向函数的入口地址,参数为一个void指针类型
(void *)fun(void *);定义一个函数,返回值为指针的函数,参数为void指针类型
void指针
指针有两个属性:指向变量/对象的地址 和长度 ,但是指针只存储地址,长度则取决于指针的类型,编译器根据指针的类型从指针指向的地址向后寻址,指针类型不同则寻址范围也不同,比如:
表示 pf 是一个指向函数入口的指针变量,该函数的返回值 ( 函数值 ) 是整型。
下面通过例子来说明用指针形式实现对函数调用的方法。
int max(int a,int b){
if(a>b)return a;
else return b;
} main(ຫໍສະໝຸດ { int max(int a,int b);
怎样说明一个函数指针变量呢 ?
为了说明一个变量 fn_pointer 的类型是"返回值为 int 的函数指针", 你可以使用下面的说明语句:
int (*fn_pointer) ();
为了让编译器能正确地解释这句语句, *fn_pointer 必须用括号围起来。若漏了这对括号, 则:
int *fn_pointer ();
函数指针 (*(void (*)( ) )0)( ) 解析C++
概述
在很多情况下,尤其是读别人所写代码的时候,对 C语言声明的理解能力变得非常重要,而C语言本身的凝练简约也使得C语言的声明常常会令人感到非常困惑,因此,在这里我用一篇的内容来集中阐述一下这个问题。
C语言void及void指针
C/C++语言void及void指针1.void的含义void的字面意思是“无类型”,void*则为“无类型指针”,void*可以指向任何类型的数据。
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义:这行语句编译时会出错,提示“illegal use of type'void'”。
不过,即使void a的编译不会出错,它也没有任何实际意义。
void真正发挥的作用在于:(1)对函数返回的限定;(2)对函数参数的限定。
我们将在第三节对以上二点进行具体说明。
众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。
例如:其中p1=p2语句会编译出错,提示“'=':cannot convert from'int*'to'float*'”,必须改为:而void*则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:但这并不意味着,void*也可以无需强制类型转换地赋给其它类型的指针。
因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。
道理很简单,我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。
下面的语句编译出错:提示“'=':cannot convert from'void*'to'int*'”。
2.void的使用下面给出void关键字的使用规则:规则一如果函数没有返回值,那么应声明为void类型在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。
但是许多程序员却误以为其为void类型。
例如:程序运行的结果为输出:2+3=5这说明不加返回值说明的函数的确为int函数。
C语言基础知识函数指针指针函数(定义格式作用及用法说明)
C语言基础知识函数指针指针函数(定义格式作用及用法说明)函数指针(Function Pointers)是C语言中一种特殊的指针,它可以指向一个函数。
不同于普通指针,函数指针表示指向一个函数的入口地址,而且可以在运行时动态改变。
函数指针可以用来实现函数的参数传递、函数的地址调用、函数的回调机制以及多态等功能。
一、定义格式函数指针可以像普通指针一样进行定义,只不过指针的指向类型不是普通的数据类型,而是函数,它的定义格式如下:(1)一般的函数指针:<return_type> (*ptr)(param_list);(2)函数指针数组:<return_type> (*ptr)(param_list)[size];(3)函数指针数组指针:<return_type> (*ptr[size])(param_list);(4)带参数的函数指针:<return_type> (*ptr)(type param);(5)可变参数的函数指针:<return_type> (*ptr)(param_type, ...);(6)函数指针的指针:<return_type> (**ptr)(param_list);二、作用(1)函数指针可以在函数内外传递,从而可以实现函数参数的传递,实现函数的“回调”机制;(2)函数指针可以用来实现回调函数,比如设计回调函数时,可以将函数指针作为参数,当一些事件发生时,函数指针被调用,来执行特定的操作;(3)函数指针可以实现函数的多态,函数指针可以用来指向不同参数类型的函数,从而实现函数的多态。
三、用法。
c陷阱与缺陷《C陷阱和缺陷》读书笔记 ——前车的覆 后车的鉴
c陷阱与缺陷:《C陷阱和缺陷》读书笔记——前车的覆 后车的鉴疯狂代码 / ĵ:http://BlogDigest/Article76354.html《C陷阱与缺陷》,作者:Andrew Koenig [美], 译:高 巍 。
; ; ; 这本书是作者以自己发表过的一篇论文为基础,结合自己的工作经验扩展而成。
我看过之后“吃了一斤”,它跟以往我看过的教程完全不一样,它涉及到C的各个方面,细微、精辟。
用两个字形容,那就是实用。
我不打算把整本书抄一遍,只对我认为“比较重要”(其实没有哪一点是不重要的)的部分做了笔记,并且是简要提取了其中的主要内容,以及相应的小例子,希望再次回顾的时候提高效率。
如果你感到意犹未尽,可以下载来看。
C陷阱与缺陷 下载 ; 1.1 = 不同于 ==; ; ; 来看这样一个例子,while (c=' ' || c== '\t' || c=='\n'); ; ; c = getc(f);; ; ; 由于程序员在比较字符‘ ’和变量c时,误将 == 写成 = ,那么while后的表达式恒为 1,因为' '不等于零,它的ASCII码值为32。
; ; ; 为了避免这种情况,我们可以这样写 while(''==c || '\t'== c || '\n'==c) ,这样即使不小心将 == 写成 =,编译器也会报错。
; ★ ★ 在C中,单引号括起来表示一个整数,双引号括起来表示指针。
例如,字符和字符串。
1.3 词法分析中的“贪心法”; ; ; C编译器读入一个符号的规则:每一个符号应该包含尽可能多的字符,方向为自左向右。
; ; ; 例如,a---b <==> (a--) -b; ; ; 而 y = x/*p; 中 /* 被编译器理解为一段注释的开始,如果本意是用x除以p所指向的值,应该重写如下y = x/ *p; 或更加清楚一点,写作 y = x/(*p);; ★ ★ 在用双引号括起来的字符串中,注释符 /* 属于字符串的一部分,而在注释中出现的双引号""属于注释的一部分。
指针作为返回值
指针作为函数的返回值1 指针作为函数的返回值指针值也可以作为函数的返回值。
这种情况下函数的返回值类型需要定义成指针变量类型。
返回指针值的函数的一般定义格式为:数据类型*函数名称(形式参数列表)例如:float *Func(float x, float y);该函数的形式参数是两个float型的变量,返回一个float型变量的指针。
下面是一个返回指针值的函数的例子:long score[10]={1,2,3,4,5,6,7,8,9,10};long *GetMax();main(){long *p;p=GetMax();printf("Max value in array is %d", *p);}long *GetMax(){long temp;int i, pos=0;temp=score[0];for(i=0;i<10;i++)if(score[i]>temp){temp=score[i];pos=i;}return &score[pos];}程序运行的结果为:Max value in array is 10上面的例子中,GetMax函数没有任何形式参数,该函数返回一个指针值。
注意long型数组score是一个全局变量,它有10个已经初始化过的元素。
GetMax函数中,我们用临时变量temp比较记录全局数组score里最大的元素,同时用pos 记录最大的元素的数组下标号。
循环结束后,返回的是数组中值最大的元素的地址值,即该元素的指针值。
注意因为数组是全局变量,GetMax函数调用结束后,数组元素在内存中仍然存在,因此GetMax函数返回的指针值是有效的。
main函数中定义了一个指针变量p,调用了GetMax函数,将返回的指针值赋给了指针变量p,现在p指向了数组score里最大的元素,*p对应了score里最大的元素的值。
后续的printf打印了*p值。
整数强转void指针
整数强转void指针
在C语言中,可以将整数强制转换为void指针,因为void指针是一种通用类型,可以指向任何类型的数据。
下面是一个示例代码,将整数强制转换为void指针:```c
int num = 10;
void *ptr = (void*)num;
```
在上述代码中,首先定义了一个整数变量num,然后使用(void*)运算符将其强制转换为void指针类型,并将结果存储在指针变量ptr中。
需要注意的是,void指针本身不具备指向任何有效数据的能力,因此在使用void指针时需要进行类型转换,以便正确地访问和操作数据。
另外,将整数强制转换为void指针可能会在跨平台移植中出现问题,因此在实际编程中应尽量避免这种用法。
将0转型为“指向返回值为void的函数的指针” (void (x)())0
(void (*)())0 的含义(void (*)())0 的含义:1. fp是一个指针{有*},她指向返回值为void{有(void)}类型的函数{有()}:void (*fp)();调用方式简写为:(*fp)();2. 制作其对应的类型强制转换符:void (*)()3. 存储位置为0 的强制转换为一个指向返回值为void类型的函数的指针:(void (*)())04. 用上式代替fp,从而实现调用存储位置为0的子例程:(*(void(*)())0)();5. 利用typedef简化:typedef void (*funcptr)(); (*(funcptr)0)();(void (*)())0 的含义:实际上就是将地址0强制转换为一个指向返回值为void类型的函数的指针。
下面将相关基础知识进行介绍,其中参考了网上一些文章,名单不再列出,谢谢各位大虾的贡献:1、c语言的声明2、类型转换符的制作3、signal函数分析4、typedef用法5、const用法6、typedef的好处1 C语言的声明声明由两部分组成:类型以及声明符:float f,g;float ((f));//对其求值时,((f))的类型为浮点型,可以推知,f也是浮点型float *g(),(*h)();//g是函数,该函数的返回类型为指向浮点数的指针//h是个指针,且是一个函数指针,该指针指向函数返回值,该返回值是一个float型(*fp)()简写为fp()//函数调用方式,其中fp为函数指针*((*fp)())简写为*fp()//函数返回值为某个类型的指针、2 类型转换符制作类型转换符制作:1、去掉声明中的变量名、分号;2、将剩余部分用括号"封装"起来float (*h)(); --> (float (*)())//指向返回值为float型的函数指针的类型转换符(*0)();//返回值为void类型的函数指针如果fp是一个指向返回值为void类型的函数的指针,那么(*fp)()的值为 void,fp的声明如下:void (*fp)();因此可以用下式完成调用存储位置为0的子例程:void (*fp)(); (*fp)();这种写法的代价是多声明了一个哑变量,我们常将0转型为“指向返回值为void的函数的指针”:(void (*)())0用上式代替fp,从而得到:(*(void(*)())0)();typedef void (*funcptr)();将0转型为“指向返回值为void的函数的指针”-----(void (*)())0(*(funcptr)0)();3 signal函数signal函数接受两个参数:信号类型的整型值、指向用户提供的信号处理函数指针用户提供的信号处理函数返回值类型为:voidsignal的返回值类型:指向调用前的用户定义信号处理函数的指针下面分析 signal函数在signal.h中是如何声明的1. 用户定义信号处理函数:void sigfunc(int n){/*特定信号处理部分*/}2. sigfunc声明:void sigfunc(int);3. 假设sfp指向sigfunc函数,sigfunc函数声明:void (*sfp)(int);4. 假设sig为一整数,则 (*sfp)(sig)返回值为void类型5. sfp与signal返回值类型相同,故声明signal函数:void (*signal(something))(int);//something 为signal的参数类型//过程分析:传递一个适当的参数调用signal;对signal的返回值解引用;传递一个参数调用解引用后(void (*)())0将0转型为“指向返回值为void的函数的指针”-----(void (*)())0//得到的函数;得到返回值为void型//signal函数返回值是一个指向返回值为void类型的函数的指针6. signal其中参数为:int 、 void (*)(int),故signal函数:void (*signal(int,void(*)(int)))(int);7. 用typedef简化: typedef void (*HANDLER)(int); HANDER signal(int,HANDER);将0转型为“指向返回值为void的函数的指针”-----(void (*)())04 typedef用法例1:int* (*a[5])(int, char*);typedef int* (*PF)(int, char*);//PF是一个类型别名PF a[5];//跟int* (*a[5])(int, char*);的效果一样!//很多初学者只知道typedef char* p char;但是对于typedef的其它用法不太了解。
void指针的转换
void指针的转换
不论什么类型的指针都能够显式转换为void类型,且不会丢失数据。
例如以下⾯程序:
#include<stdio.h>
int main(void)
{
short a=5;
void *p1;
short *p2;
p1=(void *)&a;
p2=(short *)p1;
printf(“%d\n”,*p2);
return 0;
}
a的地址为0x0012ff7c。
因此p1中存放地址0x0012ff7c,其数据为5,但5不能通过p1訪问。
假设要訪问数据。
能够通过显式转换将p1转化为short类型(数据5本⾝就是short类型),即p2,此时通过调⽤p2便能够訪问数据5,其数据不会丢失。
在上⾯这个情况中,在相同长度的指针格式互相转换,其⼤⼩不变,⽽且数据不会失真。
假设⼀个void的指针被强制转换为int。
之后⼜转换为long时,⼤⼩会发⽣变化。
同⼀时候数据也会失真。
void及void指针
C/C++语言void及void指针深层探索作者:宋宝华 e-mail:21cnbao@1.概述许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误。
本文将对void关键字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧。
2.void的含义void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void 变量,让我们试着来定义:void a;这行语句编译时会出错,提示“illegal use of type 'void'”。
不过,即使void a 的编译不会出错,它也没有任何实际意义。
void真正发挥的作用在于:(1)对函数返回的限定;(2)对函数参数的限定。
我们将在第三节对以上二点进行具体说明。
众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。
例如:float *p1;int *p2;p1 = p2;其中p1 = p2语句会编译出错,提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:p1 = (float *)p2;而void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:void *p1;int *p2;p1 = p2;但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。
因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。
道理很简单,我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。
下面的语句编译出错:void *p1;int *p2;p2 = p1;提示“'=' : cannot convert from 'void *' to 'int *'”。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(void (*)())0 的含义(void (*)())0 的含义:1. fp是一个指针{有*},她指向返回值为void{有(void)}类型的函数{有()}:void (*fp)();调用方式简写为:(*fp)();2. 制作其对应的类型强制转换符:void (*)()3. 存储位置为0 的强制转换为一个指向返回值为void类型的函数的指针:(void (*)())04. 用上式代替fp,从而实现调用存储位置为0的子例程:(*(void(*)())0)();5. 利用typedef简化:typedef void (*funcptr)(); (*(funcptr)0)();(void (*)())0 的含义:实际上就是将地址0强制转换为一个指向返回值为void类型的函数的指针。
下面将相关基础知识进行介绍,其中参考了网上一些文章,名单不再列出,谢谢各位大虾的贡献:1、c语言的声明2、类型转换符的制作3、signal函数分析4、typedef用法5、const用法6、typedef的好处1 C语言的声明声明由两部分组成:类型以及声明符:float f,g;float ((f));//对其求值时,((f))的类型为浮点型,可以推知,f也是浮点型float *g(),(*h)();//g是函数,该函数的返回类型为指向浮点数的指针//h是个指针,且是一个函数指针,该指针指向函数返回值,该返回值是一个float型(*fp)()简写为fp()//函数调用方式,其中fp为函数指针*((*fp)())简写为*fp()//函数返回值为某个类型的指针、2 类型转换符制作类型转换符制作:1、去掉声明中的变量名、分号;2、将剩余部分用括号"封装"起来float (*h)(); --> (float (*)())//指向返回值为float型的函数指针的类型转换符(*0)();//返回值为void类型的函数指针如果fp是一个指向返回值为void类型的函数的指针,那么(*fp)()的值为 void,fp的声明如下:void (*fp)();因此可以用下式完成调用存储位置为0的子例程:void (*fp)(); (*fp)();这种写法的代价是多声明了一个哑变量,我们常将0转型为“指向返回值为void的函数的指针”:(void (*)())0用上式代替fp,从而得到:(*(void(*)())0)();typedef void (*funcptr)();将0转型为“指向返回值为void的函数的指针”-----(void (*)())0(*(funcptr)0)();3 signal函数signal函数接受两个参数:信号类型的整型值、指向用户提供的信号处理函数指针用户提供的信号处理函数返回值类型为:voidsignal的返回值类型:指向调用前的用户定义信号处理函数的指针下面分析 signal函数在signal.h中是如何声明的1. 用户定义信号处理函数:void sigfunc(int n){/*特定信号处理部分*/}2. sigfunc声明:void sigfunc(int);3. 假设sfp指向sigfunc函数,sigfunc函数声明:void (*sfp)(int);4. 假设sig为一整数,则 (*sfp)(sig)返回值为void类型5. sfp与signal返回值类型相同,故声明signal函数:void (*signal(something))(int);//something 为signal的参数类型//过程分析:传递一个适当的参数调用signal;对signal的返回值解引用;传递一个参数调用解引用后(void (*)())0将0转型为“指向返回值为void的函数的指针”-----(void (*)())0//得到的函数;得到返回值为void型//signal函数返回值是一个指向返回值为void类型的函数的指针6. signal其中参数为:int 、 void (*)(int),故signal函数:void (*signal(int,void(*)(int)))(int);7. 用typedef简化: typedef void (*HANDLER)(int); HANDER signal(int,HANDER);将0转型为“指向返回值为void的函数的指针”-----(void (*)())04 typedef用法例1:int* (*a[5])(int, char*);typedef int* (*PF)(int, char*);//PF是一个类型别名PF a[5];//跟int* (*a[5])(int, char*);的效果一样!//很多初学者只知道typedef char* p char;但是对于typedef的其它用法不太了解。
//Stephen Blaha对typedef用法做过一个总结:“建立一个类型别名的方法很简单,//在传统的变量声明表达式里用类型名替代变量名,然后把关键字 typedef加在该语句的开头”。
例2:void (*b[10])(void (*)());typedef void (*pfv)();typedef void (*pf_taking_pfv)(pfv);pf_taking_pfv b[10]; //跟void (*b[10]) (void (*)());的效果一样!例3:double(*)()(*pa)[9];typedef double(*PF)();const和volatile在类型声明中的位置。
5 const用法(volatile是一样的)volatile修饰的量就是很容易变化,不稳定的量,它可能被其它线程,操作系统,硬件等等在未知的时间改变,所以它被存储在内存中,每次取用它的时候都只能在内存中去读取,它不能被编译器优化放在内部寄存器中。
const int; //int是constconst char*;//char是constchar* const;//*(指针)是constconst char* const;//char和*都是const另外一个对等的写法(const在后面):int const; //int是constchar const*;//char是constchar* const;//*(指针)是constchar const* const;//char和*都是constconst在后面有两个好处:A.const所修饰的类型正好是在它前面的那一个B.用到typedef的类型别名定义时,如typedef char* pchar,当const在前面的时候,就是const pchar,它的真实含义是char* const,而不是const char* 。
将0转型为“指向返回值为void的函数的指针”-----(void (*)())06 typedef的好处使用 typedef 来编写更美观和可读的代码。
所谓美观,意指typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性,使代码更健壮。
typedef使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。
类型出现在所声明的变量名字中,位于typedef关键字右边:typedef int size;注意typedef并不创建新的类型,仅仅为现有类型添加一个同义字,使用 size:void measure(size * psz);size array[4];typedef 可以掩饰复合类型,如指针和数组:char line[81]; char text[81];定义一个typedef,每当要用到相同类型和大小的数组时,可以这样:typedef char Line[81];Line text, secondline;getline(text);同样,可以象下面这样隐藏指针语法:typedef char * pstr;int mystrcmp(pstr, pstr);第一个 typedef 陷阱:标准函数 strcmp()有两个const char *类型的参数。
因此,它可能会误导人们象下面这样声明:int mystrcmp(const pstr, const pstr);const pstr被编译器解释为char * const(一个指向 char 的常量指针),而不是const char *(指向常量 char 的指针)。
这个问题很容易解决:typedef const char * cpstr;int mystrcmp(cpstr, cpstr);typedef 行为有点像 #define 宏,用其实际类型替代同义字。
不同点是typedef在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。
例如:typedef int (*PF) (const char *, const char *);这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个int 类型的返回值。
如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:PF Register(PF pf);Register()的参数是一个PF类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同,如果不用 typedef,如何实现这个声明的:int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。
这并不是说typedef会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象static,extern 等类型的变量声明。
第二个陷阱:typedef register int FAST_COUNTER; // 错误编译通不过不能在声明中有多个存储类关键字,因为符号 typedef 已经占据了存储类关键字的位置。
在 typedef 声明中不能用 register(或任何其它存储类关键字)。
typedef定义机器无关的类型:例如定义一个叫 REAL 的浮点类型,在目标机器上它可以获得最高的精度:typedef long double REAL;typedef double REAL;//不支持 long double 的机器上typedef float REAL;//不支持double 的机器上不用修改源代码,便可在每一种平台上编译这个使用 REAL 类型的应用程序。