鱼C论坛

 找回密码
 立即注册
楼主: 竹逸

[已解决]malloc函数申请的内存空间为什么要进行类型强制转换?

[复制链接]
发表于 2022-11-26 14:34:48 | 显示全部楼层
竹逸 发表于 2022-11-26 14:26
好神奇,为什么我问问题之前,和你同样的代码无法编译,现在又能编译了你看我问题描述,描述 ...

17楼有间接答案
因为我已经回答了这个问题,在前面

再复制一遍
'''
先把我的回复从上到下看一遍,然后再提出你的问题
'''
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 14:38:32 | 显示全部楼层
竹逸 发表于 2022-11-26 14:26
好神奇,为什么我问问题之前,和你同样的代码无法编译,现在又能编译了你看我问题描述,描述 ...

         不使用强制转换 VC 可以正常编译,int * 和 char * 型的都可以,但是 gcc 不行,哪怕是 char * 型的都不行。
D:\[00.Exerciese.2022]\C>g++ -o x x.c
x.c: In function 'int main()':
x.c:6:25: error: invalid conversion from 'void*' to 'int*' [-fpermissive]
         int * p = malloc(4) ;
                         ^
D:\[00.Exerciese.2022]\C>g++ -o x x.c
x.c: In function 'int main()':
x.c:6:26: error: invalid conversion from 'void*' to 'char*' [-fpermissive]
         char * p = malloc(4) ;
                          ^
D:\[00.Exerciese.2022]\C>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 14:42:54 | 显示全部楼层
本帖最后由 竹逸 于 2022-11-26 14:46 编辑


你的代码没问题,我都看了,是我的编译器有问题,我用的是vc6,在问问题之前不强制转换会无法编译,才会发这个帖子,现在又可以编译了,这就见鬼了,我那自己的理解是根据无法编译得出理解的,要是能编译也就不会那样理解了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 14:51:19 | 显示全部楼层
void *可以隐式转换到任何其他指针类型
任何其他指针类型也可以隐式转换到void *
这没有任何问题

下面的代码没有语法错误,运行也不会报错,运行结果没有意义,就仅仅是为了说明这个结论
sh-5.1$ cat main.c
#include <stdio.h>

void *func(void *data) {
    char *c = data;
    *c = '0';
    return data + 1;
}

int main(void) {
    int x = 123;
    float *pf = func(&x);
    unsigned char *c = func(pf);
    *c = '1';
    printf("%x\n", x);
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
313030
sh-5.1$
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 14:52:33 | 显示全部楼层
竹逸 发表于 2022-11-26 14:42
你的代码没问题,我都看了,是我的编译器有问题,我用的是vc6,在问问题之前不强制转换会无法编译,才 ...

6楼也看了,能不能看懂?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 14:59:26 | 显示全部楼层
人造人 发表于 2022-11-26 14:51
void *可以隐式转换到任何其他指针类型
任何其他指针类型也可以隐式转换到void *
这没有任何问题

在VC6里你这代码报错,报错原因:'void *' : unknown size

VC6真的要扔掉了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 15:00:41 | 显示全部楼层
人造人 发表于 2022-11-26 14:52
6楼也看了,能不能看懂?

能,你的代码都看得懂,是VC6编译器的问题,我的任何理解都是根据编译器的结果来推导的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:07:50 | 显示全部楼层
memset这个函数用来初始化一段内存空间
       void *memset(void *s, int c, size_t n);
这是这个函数的声明,看到了吧,void * 类型的
可是你写代码的时候强制转换到void * 了?
memset((void *)a, 0, sizeof(int) * 10);
但是为什么你们就是要这样写代码?
int *a = (int *)malloc(sizeof(int) * 10);
为什么就是要强制转换?这不是都一样么?
要么都转,要么都不转,这是为了统一编码风格,这我能理解,但是为什么就是要对malloc区别对待?

你说你要让这个代码在C++中也可用?
是的,在C++中如果不强制转换类型,是会编译报错的,因为C++中void *和其他指针类型不在隐式转换
但是我想说,你在C++中用什么malloc/free,C++中有自己的,很好用的new/delete你不用,你就是要用C的malloc/free ?
你是闲bug不够多是不是?
C++中用malloc/free是很有可能会出问题的

sh-5.1$ cat main.c
#include <stdio.h>
#include <string.h>

int main(void) {
    int a[10];
    memset(a, 0, sizeof(int) * 10);
    //memset((void *)a, 0, sizeof(int) * 10);
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:17:05 | 显示全部楼层
竹逸 发表于 2022-11-26 15:00
能,你的代码都看得懂,是VC6编译器的问题,我的任何理解都是根据编译器的结果来推导的

你还是没看懂呀,那我就解释一下吧
一开始这个代码用C编译器gcc编译,没有问题
然后又用C++编译器g++编译,是同一个代码,但是报错了
因为
C中void *和其他指针类型是可以隐式转换的
而C++中void *和其他指针类型不在隐式转换
所以在C++中得强制转换
这就是这个写法的来源
int *a = (int *)malloc(sizeof(int) * 10);
因为报错了,然后看到有人说强制转换一下,他们强制转换了,然后就正常了,然后他们就记住了,用malloc一定要强制转换,不然是会报错的
可是,他们根本就没有意识到他们是在用C++环境学C语言
说简单点就是,他们在用C++的编译器编译C语言的代码
那么问题来了,这个他们里面有没有你?
你看一下你的源代码文件名的后缀是不是 .c,.c是C语言,.cpp是C++
你再检查一下你是不是用的C++编译器
sh-5.1$ cat main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char *a = malloc(3);
    a[0] = 'o';
    a[1] = 'k';
    a[2] = '\0';
    puts(a);
    free(a);
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
ok
sh-5.1$ g++ -g -Wall -o main main.c
main.c: In function ‘int main()’:
main.c:5:21: error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]
    5 |     char *a = malloc(3);
      |               ~~~~~~^~~
      |                     |
      |                     void*
sh-5.1$
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:19:06 | 显示全部楼层
我的每一个回复对你都是有帮助的,希望不要忽略
如果哪个看不懂的话,说出来,我给你解释
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 15:20:45 | 显示全部楼层
人造人 发表于 2022-11-26 15:17
你还是没看懂呀,那我就解释一下吧
一开始这个代码用C编译器gcc编译,没有问题
然后又用C++编译器g++编 ...

我用的是VC6编译器,不知道是不是C++编译器,虽然代码文件的后缀是 .c
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:26:00 | 显示全部楼层
竹逸 发表于 2022-11-26 15:20
我用的是VC6编译器,不知道是不是C++编译器,虽然代码文件的后缀是 .c

我很久之前就不用vc6了,我也不知道
不过如果你的后缀是 .c 的话,问题应该不大
建议还是换一个好点的编译器吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:30:46 | 显示全部楼层
竹逸 发表于 2022-11-26 13:35
我发现不进行类型转换,可以用字符型指针来接收这段空间的起始地址,但int型指针就无法编译

所以为什么无法编译呢?
很奇怪,一定是你的操作不对,你再想想,想想你是怎么操作的,为什么会无法编译呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 15:49:11 | 显示全部楼层
人造人 发表于 2022-11-26 15:30
所以为什么无法编译呢?
很奇怪,一定是你的操作不对,你再想想,想想你是怎么操作的,为什么会无法编译 ...

问问题之前代码绝对没问题,我保证代码的正确性,就是不知道为啥无法编译,可能是和上一个打开的文件有关?复制了你的代码,重新编译下就又能编译了,我也觉得奇怪的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:58:40 | 显示全部楼层
竹逸 发表于 2022-11-26 14:21
是的,我学汇编的时候就是小甲鱼8086的CPU知识,所以也就只能用8086的来描述,而且malloc函数却是也是从 ...

那就用16位的汇编语言来研究也是可以的,你现在应该就差一个tc编译器了吧,弄一个
tc是16位的C语言编译器
可以用tc编译器来编译C语言代码,用debug这个软件来反汇编
如果你有兴趣的话,可以研究研究下面的反汇编代码

1.png
2.png
3.png
4.png
11B3:0291 55            PUSH    BP
11B3:0292 8BEC          MOV     BP,SP
11B3:0294 56            PUSH    SI
11B3:0295 B89102        MOV     AX,0291
11B3:0298 50            PUSH    AX
11B3:0299 B8AA00        MOV     AX,00AA
11B3:029C 50            PUSH    AX
11B3:029D E8630C        CALL    0F03
11B3:02A0 59            POP     CX
11B3:02A1 59            POP     CX
11B3:02A2 B80600        MOV     AX,0006
11B3:02A5 50            PUSH    AX
11B3:02A6 E8CE08        CALL    0B77
11B3:02A9 59            POP     CX
11B3:02AA 8BF0          MOV     SI,AX
11B3:02AC C7046400      MOV     WORD PTR [SI],0064
11B3:02B0 C74402C800    MOV     WORD PTR [SI+02],00C8
11B3:02B5 8B04          MOV     AX,[SI]
11B3:02B7 034402        ADD     AX,[SI+02]
11B3:02BA 894404        MOV     [SI+04],AX
11B3:02BD FF7404        PUSH    [SI+04]
11B3:02C0 B8B400        MOV     AX,00B4
11B3:02C3 50            PUSH    AX
11B3:02C4 E83C0C        CALL    0F03
11B3:02C7 59            POP     CX
11B3:02C8 59            POP     CX
11B3:02C9 56            PUSH    SI
11B3:02CA E8DB07        CALL    0AA8
11B3:02CD 59            POP     CX
11B3:02CE 33C0          XOR     AX,AX
11B3:02D0 EB00          JMP     02D2
11B3:02D2 5E            POP     SI
11B3:02D3 5D            POP     BP
11B3:02D4 C3            RET

其实你应该尽快的往后学,后面有更好的,更方便的工具
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 15:59:51 | 显示全部楼层
竹逸 发表于 2022-11-26 15:49
问问题之前代码绝对没问题,我保证代码的正确性,就是不知道为啥无法编译,可能是和上一个打开的文件有关 ...

这个我就不知道了,不过我感觉就是你的操作问题
^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 16:05:09 | 显示全部楼层
人造人 发表于 2022-11-26 15:58
那就用16位的汇编语言来研究也是可以的,你现在应该就差一个tc编译器了吧,弄一个
tc是16位的C语言编译 ...

汇编代码看着 头疼,我才学了一点点,没学完
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:05:47 | 显示全部楼层
竹逸 发表于 2022-11-26 16:05
汇编代码看着 头疼,我才学了一点点,没学完

^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:09:19 | 显示全部楼层
jackz007 发表于 2022-11-26 14:28
你不用关心堆指针的事情,因为,这个完全是由操作系统在掌控(malloc() 是 Windows API),你 ...

malloc() 是 Windows API

malloc 不是 windows api,malloc是C语言的库函数
linux下面的C语言也可以使用malloc函数
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:10:43 | 显示全部楼层
jackz007 发表于 2022-11-26 14:38
不使用强制转换 VC 可以正常编译,int * 和 char * 型的都可以,但是 gcc 不行,哪怕是 char *  ...

因为你使用的g++,这是C++编译器
gcc才是C语言编译器
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-26 10:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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