人造人
发表于 2022-11-26 14:34:48
竹逸 发表于 2022-11-26 14:26
好神奇,为什么我问问题之前,和你同样的代码无法编译,现在又能编译了你看我问题描述,描述 ...
17楼有间接答案
因为我已经回答了这个问题,在前面
再复制一遍
'''
先把我的回复从上到下看一遍,然后再提出你的问题
'''
jackz007
发表于 2022-11-26 14:38:32
竹逸 发表于 2022-11-26 14:26
好神奇,为什么我问问题之前,和你同样的代码无法编译,现在又能编译了你看我问题描述,描述 ...
不使用强制转换 VC 可以正常编译,int * 和 char * 型的都可以,但是 gcc 不行,哪怕是 char * 型的都不行。
D:\\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:\\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:\\C>
竹逸
发表于 2022-11-26 14:42:54
本帖最后由 竹逸 于 2022-11-26 14:46 编辑
人造人 发表于 2022-11-26 14:32
17楼
https://fishc.com.cn/forum.php?mod=redirect&goto=findpost&ptid=221281&pid=6063298
你的代码没问题,我都看了,是我的编译器有问题,我用的是vc6,在问问题之前不强制转换会无法编译,才会发这个帖子,现在又可以编译了,这就见鬼了,我那自己的理解是根据无法编译得出理解的,要是能编译也就不会那样理解了{:5_99:}
人造人
发表于 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$
人造人
发表于 2022-11-26 14:52:33
竹逸 发表于 2022-11-26 14:42
你的代码没问题,我都看了,是我的编译器有问题,我用的是vc6,在问问题之前不强制转换会无法编译,才 ...
6楼也看了,能不能看懂?
竹逸
发表于 2022-11-26 14:59:26
人造人 发表于 2022-11-26 14:51
void *可以隐式转换到任何其他指针类型
任何其他指针类型也可以隐式转换到void *
这没有任何问题
在VC6里你这代码报错,报错原因:'void *' : unknown size{:5_99:}
VC6真的要扔掉了
竹逸
发表于 2022-11-26 15:00:41
人造人 发表于 2022-11-26 14:52
6楼也看了,能不能看懂?
能,你的代码都看得懂,是VC6编译器的问题,我的任何理解都是根据编译器的结果来推导的{:5_99:}
人造人
发表于 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;
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$
人造人
发表于 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 = 'o';
a = 'k';
a = '\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$
人造人
发表于 2022-11-26 15:19:06
我的每一个回复对你都是有帮助的,希望不要忽略
如果哪个看不懂的话,说出来,我给你解释
竹逸
发表于 2022-11-26 15:20:45
人造人 发表于 2022-11-26 15:17
你还是没看懂呀,那我就解释一下吧
一开始这个代码用C编译器gcc编译,没有问题
然后又用C++编译器g++编 ...
我用的是VC6编译器,不知道是不是C++编译器,虽然代码文件的后缀是 .c{:5_94:}
人造人
发表于 2022-11-26 15:26:00
竹逸 发表于 2022-11-26 15:20
我用的是VC6编译器,不知道是不是C++编译器,虽然代码文件的后缀是 .c
我很久之前就不用vc6了,我也不知道
不过如果你的后缀是 .c 的话,问题应该不大
建议还是换一个好点的编译器吧
人造人
发表于 2022-11-26 15:30:46
竹逸 发表于 2022-11-26 13:35
我发现不进行类型转换,可以用字符型指针来接收这段空间的起始地址,但int型指针就无法编译
所以为什么无法编译呢?
很奇怪,一定是你的操作不对,你再想想,想想你是怎么操作的,为什么会无法编译呢?
竹逸
发表于 2022-11-26 15:49:11
人造人 发表于 2022-11-26 15:30
所以为什么无法编译呢?
很奇怪,一定是你的操作不对,你再想想,想想你是怎么操作的,为什么会无法编译 ...
问问题之前代码绝对没问题,我保证代码的正确性,就是不知道为啥无法编译,可能是和上一个打开的文件有关?复制了你的代码,重新编译下就又能编译了,我也觉得奇怪的{:5_99:}
人造人
发表于 2022-11-26 15:58:40
竹逸 发表于 2022-11-26 14:21
是的,我学汇编的时候就是小甲鱼8086的CPU知识,所以也就只能用8086的来描述,而且malloc函数却是也是从 ...
那就用16位的汇编语言来研究也是可以的,你现在应该就差一个tc编译器了吧,弄一个
tc是16位的C语言编译器
可以用tc编译器来编译C语言代码,用debug这个软件来反汇编
如果你有兴趣的话,可以研究研究下面的反汇编代码
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 ,0064
11B3:02B0 C74402C800 MOV WORD PTR ,00C8
11B3:02B5 8B04 MOV AX,
11B3:02B7 034402 ADD AX,
11B3:02BA 894404 MOV ,AX
11B3:02BD FF7404 PUSH
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
其实你应该尽快的往后学,后面有更好的,更方便的工具
人造人
发表于 2022-11-26 15:59:51
竹逸 发表于 2022-11-26 15:49
问问题之前代码绝对没问题,我保证代码的正确性,就是不知道为啥无法编译,可能是和上一个打开的文件有关 ...
这个我就不知道了,不过我感觉就是你的操作问题
^_^
竹逸
发表于 2022-11-26 16:05:09
人造人 发表于 2022-11-26 15:58
那就用16位的汇编语言来研究也是可以的,你现在应该就差一个tc编译器了吧,弄一个
tc是16位的C语言编译 ...
汇编代码看着 头疼,我才学了一点点,没学完{:5_99:}
人造人
发表于 2022-11-26 16:05:47
竹逸 发表于 2022-11-26 16:05
汇编代码看着 头疼,我才学了一点点,没学完
^_^
人造人
发表于 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函数
人造人
发表于 2022-11-26 16:10:43
jackz007 发表于 2022-11-26 14:38
不使用强制转换 VC 可以正常编译,int * 和 char * 型的都可以,但是 gcc 不行,哪怕是 char *...
因为你使用的g++,这是C++编译器
gcc才是C语言编译器