游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5757|回复: 12

关于函数指针和共用体的问题

[复制链接]

3

主题

14

帖子

57

积分

注册会员

Rank: 2

积分
57
发表于 2008-4-26 18:58:00 | 显示全部楼层 |阅读模式
// define.h
#ifndef        DEFINE_H_
#define DEFINE_H_

struct func_type
{
        char* m_name;
        union
        {
                void (*p1)();
                void (*p2)(int);
        } m_func;
};

void print();
void print(int);

#endif

// define.cpp
#include "define.h"

void print1()
{
}

void print2(int n)
{
}

func_type func_table[] = {
        {"print1", print1},
        {"print2", print2}
};

int main()
{
        return 0;
}

上段代码为什么不能编译通过呢,我函数指针用的不大多,哪位高手来解释下,先谢过了

3

主题

14

帖子

57

积分

注册会员

Rank: 2

积分
57
 楼主| 发表于 2008-4-26 19:09:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

没有大侠来解决下么?

1

主题

13

帖子

29

积分

注册会员

Rank: 2

积分
29
发表于 2008-4-28 00:19:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

你的 char* m_name;
是 char *
可是 "print1"  是 const char *
类型不对

所以你可以先试试看
下面这个能通过吗?

1

主题

13

帖子

29

积分

注册会员

Rank: 2

积分
29
发表于 2008-4-28 00:20:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

你的 char* m_name;
是 char *
可是 "print1"  是 const char *
类型不对

所以你可以先试试看
下面这个能通过吗?
const char *a="a";
char *b=a;

1

主题

50

帖子

52

积分

注册会员

Rank: 2

积分
52
发表于 2008-4-28 02:14:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

楼主的代码有两大问题:
一:   普通字符串编译器默认类型为const char[],你不能使用char *去指向const char [].(其实就是 const char []无法隐式转换为 char *)
代码应该改为:
struct func_type
{
char m_name[40];
union
{
    void (*p1)();
    void (*p2)(int);
} m_func;
};
如果要使用char * 那么应该这么初始化结构更好的做法,如果不改动字符串,应该把
所有的char *和char []改为const char *和 const char [])
char func_name1[] = "print1";
char func_name2[] = "print2";
func_type func_table[] = {
   { func_name1, print1},     //char []类型这里会被编译器转换为 char *
   { func_name2, print2}      //char []类型这里会被编译器转换为 char *
};

二: 编译器不能成功编译代码是因为你对union语义理解不正确, union的正确语义应该是同样的数据(内存地址)
表现多种类型.
union的大小为最大的类型,比如: union test { int i; char c;}; //sizeof(test) = 4 bytes
当你初始化union时其他类型会被编译器自动转型为union声明中最大的类型.
比如: test t[] = { 1, '1'};   编译器会把'1'char 转型为int然后贮存.
char c = t[1]; 这里编译器会把 '1' int 转型为char 然后赋值给 c

基础类型编译器都会隐式强制帮你转换,当遇到复杂类型就需要自己手动转换.
代码改为:
typedef void (*pfvv)();
typedef void (*pfvi)(int);
char func_name1[] = "print1";
char func_name2[] = "print2";
func_type func_table[] = {
   { func_name1, print1},
   { func_name2, (pfvv)print2}  //强制类型转换
};
函数指针类型所占用空间是一样的,但是不同类型返回值和参数的函数指针之间是不能隐式转换的,
所以编译器无能为力,你必须手动强制转化才能通过编译.
pfvv pfvv1 = fun_table[0].m_func.p1; //这里取得的默认类型为 void (*pfvv)()
pfvi pfvi1 = fun_table[0].m_func.p2; //这里取得的默认类型为 void (*pfvi)(int)
                                     //注意这里编译器自动为 你转型

备注:如果union所含类型所占的内存空间都是一样的,初始化union的时候则默认储存类型则为第一个声明的类型.这也是楼主原始代码不能编译通过的原因,void (pfvv)()的声明次序在前,所以void (*pfvi)(int)必须转型为void(*pfvv)(),由于编译器不能隐式转换,所以就必须强制类型转换才能通过编译.







1

主题

50

帖子

52

积分

注册会员

Rank: 2

积分
52
发表于 2008-4-28 02:56:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

1.数组与指针
char str[] = "12345";           //编译器自动为你计算数组长度
printf("%d \n", sizeof(str));   //打印出编译器之前为你计算的数组长度   6

char *str1 = str;               //这里出现隐式类型转换 char [6] 转换为 char *
printf("%d \n", sizeof(str1));  //打印出指针大小      4 bytes

大部分人认为 数组类型 char [] 和 指针类型char *是一样的 其实还是有差别的

2.数组类型退化指针类型
void str_print(char *str)             //void str_print(char str[])
{                                     //void str_print(char str[6])
        printf("%s \n", str);      //虽然上面参数类型为char []和char [6]但是还是被逃不了被编译器
        printf("%d \n", sizeof(str)); //退化为char *的命运  这里打印出指针大小 4bytes
}

char str[] = "12345";           //编译器自动为你计算数组长度
printf("%d \n", sizeof(str));   //打印出编译器之前为你计算的数组长度   6
str_print(str);   

3. const 转换 nonconst
const char cstr[] = "123456";
char *str2 = cstr;             //编译器报错
                               //无法从“const char [7]”转换为“char*”
改为:
const char cstr[] = "123456";
char *str2 = (char *)cstr;    //强制转换 编译通过
                              //其实这里编译器会生成临时变量
                              //char __temp[7];
                              //memcpy(__temp, cstr, 7 * sizeof(char));
                              //str2 = &__temp;
转型const到nonconst会带来额外内存的开销,所以编译器不会隐式转型,但是你可以强制
转型,但你必须知道这样做的代价.


1

主题

50

帖子

52

积分

注册会员

Rank: 2

积分
52
发表于 2008-4-28 03:18:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

以上为我个人对C编译器的理解,可能会有偏差,望高手指出.(没实现过,等能力够我会做一个)
不过我认为用来解除楼主的疑惑应该解释的够了.其实我对编译技术很有兴趣.我始终认为如果对编译器越了解那么对这个语言的了解层次就越深.

1

主题

50

帖子

52

积分

注册会员

Rank: 2

积分
52
发表于 2008-4-28 04:00:00 | 显示全部楼层

Re: Re:关于函数指针和共用体的问题

archmagee: Re:关于函数指针和共用体的问题

你的 char* m_name;
是 char *
可是 "print1"  是 const char *
类型不对

所以你可以先试试看
下面这个能通过吗?

你的理解是不正确的,根据语义 "print1"是一个字符串常量,字符串的定义是字符数组,所以"print1"默认类型为数组类型const char [7]
const char *的语义为指针常量,指针指向的是内存地址而不是字符串本身.
const char *str = "print1"; //这里会发生隐式类型转换
                            //const char [7] to const char *
                            //其实就是把str指向字符数组的首地址
下面来证明"print1"是const char [7]类型
int *str = "print1"; //编译报错
//error C2440: “初始化”: 无法从“const char [7]”转换为“int *”
从编译器输出我们可以看到"print1"的默认类型是const char [7]类型

类型只是用来检测数据是否合法和语义是否正确的工具,类型检测与转换也是编译时完成的,强类型语言的好处就是可以把很多不合法的数据和语义不正确的语句进行编译时期的报错.(编译时期的错误比运行时的错误要好解决的多)

3

主题

14

帖子

57

积分

注册会员

Rank: 2

积分
57
 楼主| 发表于 2008-4-29 10:46:00 | 显示全部楼层

Re: 关于函数指针和共用体的问题

俺是楼主, 路上那位大大太强了, 呵呵, 不知可否交个朋友, 我以后碰到问题可以问问你啊。 还有, 感谢上面帅哥的回答

86

主题

2251

帖子

2386

积分

金牌会员

Rank: 6Rank: 6

积分
2386
QQ
发表于 2008-4-29 11:48:00 | 显示全部楼层

Re:关于函数指针和共用体的问题

考虑到和C语言的兼容,const char*是可以赋值给char*的。所以上面那位同学的理解和实际情况还是有些偏差的。
LZ在字符指针指向字符串常量的操作上没什么问题。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-22 16:18

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表