鱼C论坛

 找回密码
 立即注册
123
返回列表 发新帖
楼主: 竹逸

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

[复制链接]
 楼主| 发表于 2022-11-26 16:11:25 | 显示全部楼层
人造人 发表于 2022-11-26 15:59
这个我就不知道了,不过我感觉就是你的操作问题
^_^
  1. #include <stdio.h>

  2. void *func(void *data)
  3. {
  4.         printf("%p\n", data);
  5.         //printf("%d\n", *data);               //这条被注释的代码为啥会报错?
  6.         printf("%d\n", sizeof(data));
  7.         printf("%d\n", sizeof(*data));      //这条代码为什么又不会报错,输出结果为啥是 1?
  8. }

  9. int main(void)
  10. {
  11.     int x = 123;
  12.     printf("%d\n", sizeof(x));
  13.     printf("%p\n", &x);
  14.     func(&x);
  15.     return 0;
  16. }
复制代码


捕获.JPG
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:34:16 | 显示全部楼层    本楼为最佳答案   

报错说 argument type 'void' is incomplete
参数类型'void'不完整
既然不完整,那还少了什么呢?
少了长度信息
完整的类型,像 int、char、short、。。。
这些是完整的类型
他们有两个属性,一个是地址,就是在内存中这个变量从哪里开始存放
另一个是长度,从这个地址开始,后面还有几个字节是属于当前这个变量的

举个例子
  1. sh-5.1$ cat main.c
  2. #include <stdio.h>

  3. int main(void) {
  4.     char a = '0';
  5.     int b = 123;
  6.     double c = 123.456;
  7.     printf("int: %zu\n", sizeof(int));
  8.     printf("double: %zu\n", sizeof(double));
  9.     printf("&a: %p\n", &a);
  10.     printf("&b: %p\n", &b);
  11.     printf("&c: %p\n", &c);
  12.     return 0;
  13. }
  14. sh-5.1$ ./main
  15. int: 4
  16. double: 8
  17. &a: 0x7fff48c90720
  18. &b: 0x7fff48c90730
  19. &c: 0x7fff48c90740
  20. sh-5.1$
复制代码


变量a是char类型,地址是 0x7fff48c90720,长度是 1
就是说a从 0x7fff48c90720 地址开始,到 0x7fff48c90721 地址结束,不包括这个地址

变量b是int类型,地址是 0x7fff48c90730,长度是 4
就是说b从 0x7fff48c90730 地址开始,到 0x7fff48c90734 地址结束,不包括这个地址

变量c是double类型,地址是 0x7fff48c90730,长度是 8
就是说c从 0x7fff48c90740 地址开始,到 0x7fff48c90748 地址结束,不包括这个地址

但是 void 没有长度信息,只有一个地址信息,这就导致在对data这个变量解引用的时候不知道使用多少个字节,就是说
是知道从哪里开始,但是不知道到哪里结束
只有一个地址信息,知道从哪里开始
没有长度信息,不知道到哪里结束
所以不能对 void * 解引用
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:37:04 | 显示全部楼层
  1. 偶然发现在C中sizeof(void)是合法的,于是,对它的作用产生了疑问。查阅资料在GNU文档中发现如下解释:

  2.     In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1. A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.
复制代码
  1. 在 GNU C 中,加法和减法运算在指向 void 的指针和指向函数的指针上受支持。这是通过将空隙或函数的大小视为 1 来完成的。这样做的结果是,在 void 和函数类型上也允许 sizeof,并返回 1。
复制代码


https://www.cnblogs.com/hellogc/p/3374756.html
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 16:37:43 | 显示全部楼层
  1. C++中sizeof(void)是不合法的,编译错误如下:

  2. void_size.c: In function ‘int main(int, char**)’:
  3. void_size.c:15: error: invalid application of ‘sizeof’ to a void type
  4. void_size.c:16: error: ISO C++ forbids applying ‘sizeof’ to an expression of function type

复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:12:26 | 显示全部楼层
人造人 发表于 2022-11-26 16:10
因为你使用的g++,这是C++编译器
gcc才是C语言编译器

        我喜欢用 g++  是因为更加严格的语法检查
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:14:00 | 显示全部楼层
人造人 发表于 2022-11-26 16:09
malloc() 是 Windows API

malloc 不是 windows api,malloc是C语言的库函数


         这一点你无须有任何的质疑,因为我是一个 Cracker,malloc() 的功能一定是依托 OS 的 API 实现的。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:18:06 | 显示全部楼层
jackz007 发表于 2022-11-26 17:14
这一点你无须有任何的质疑,因为我是一个 Cracker,malloc() 的功能一定是依托 OS 的 API 实 ...

对的,malloc要依托os的api来实现,但是malloc本身不是os的api
malloc本身是一个C语言的库函数
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:24:25 | 显示全部楼层
jackz007 发表于 2022-11-26 17:12
我喜欢用 g++  是因为更加严格的语法检查

是的,C++检查的更严格,但是你演示的内容是错误的
C语言允许 void *可以隐式转换到任何其他指针类型,任何其他指针类型也可以隐式转换到 void *
C语言允许这样的代码 int *p = malloc(4);
但是你演示的内容的结果是这是错误的代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:24:27 | 显示全部楼层
人造人 发表于 2022-11-26 17:18
对的,malloc要依托os的api来实现,但是malloc本身不是os的api
malloc本身是一个C语言的库函数

  1. 00401100  /$  8BFF                       mov     edi, edi                                            <--- malloc()
  2. 00401102  |.  55                         push    ebp
  3. 00401103  |.  8BEC                       mov     ebp, esp
  4. 00401105  |.  56                         push    esi
  5. 00401106  |.  8B75 08                    mov     esi, dword ptr [ebp+8]
  6. 00401109  |.  83FE E0                    cmp     esi, -20
  7. 0040110C  |.  0F87 A1000000              ja      004011B3
  8. 00401112  |.  53                         push    ebx
  9. 00401113  |.  57                         push    edi
  10. 00401114  |.  8B3D 08804000              mov     edi, dword ptr [<&KERNEL32.HeapAlloc>]              <--- edi = ntdll.RtlAllocateHeap
  11. 0040111A  |>  833D 6CAC4000 00           /cmp     dword ptr [40AC6C], 0
  12. 00401121  |.  75 18                      |jnz     short 0040113B
  13. 00401123  |.  E8 F7150000                |call    0040271F
  14. 00401128  |.  6A 1E                      |push    1E
  15. 0040112A  |.  E8 45140000                |call    00402574
  16. 0040112F  |.  68 FF000000                |push    0FF
  17. 00401134  |.  E8 87110000                |call    004022C0
  18. 00401139  |.  59                         |pop     ecx
  19. 0040113A  |.  59                         |pop     ecx
  20. 0040113B  |>  A1 F4B74000                |mov     eax, dword ptr [40B7F4]
  21. 00401140  |.  83F8 01                    |cmp     eax, 1
  22. 00401143  |.  75 0E                      |jnz     short 00401153
  23. 00401145  |.  85F6                       |test    esi, esi
  24. 00401147  |.  74 04                      |je      short 0040114D
  25. 00401149  |.  8BC6                       |mov     eax, esi
  26. 0040114B  |.  EB 03                      |jmp     short 00401150
  27. 0040114D  |>  33C0                       |xor     eax, eax
  28. 0040114F  |.  40                         |inc     eax
  29. 00401150  |>  50                         |push    eax
  30. 00401151  |.  EB 1C                      |jmp     short 0040116F
  31. 00401153  |>  83F8 03                    |cmp     eax, 3
  32. 00401156  |.  75 0B                      |jnz     short 00401163
  33. 00401158  |.  56                         |push    esi
  34. 00401159  |.  E8 53FFFFFF                |call    004010B1
  35. 0040115E  |.  59                         |pop     ecx
  36. 0040115F  |.  85C0                       |test    eax, eax
  37. 00401161  |.  75 16                      |jnz     short 00401179
  38. 00401163  |>  85F6                       |test    esi, esi
  39. 00401165  |.  75 01                      |jnz     short 00401168
  40. 00401167  |.  46                         |inc     esi
  41. 00401168  |>  83C6 0F                    |add     esi, 0F
  42. 0040116B  |.  83E6 F0                    |and     esi, FFFFFFF0
  43. 0040116E  |.  56                         |push    esi
  44. 0040116F  |>  6A 00                      |push    0
  45. 00401171  |.  FF35 6CAC4000              |push    dword ptr [40AC6C]
  46. 00401177  |.  FFD7                       |call    edi                                                 <--- 调用 ntdll.RtlAllocateHeap()
  47. 00401179  |>  8BD8                       |mov     ebx, eax
  48. 0040117B  |.  85DB                       |test    ebx, ebx
  49. 0040117D  |.  75 2E                      |jnz     short 004011AD
  50. 0040117F  |.  6A 0C                      |push    0C
  51. 00401181  |.  5E                         |pop     esi
  52. 00401182  |.  3905 10B14000              |cmp     dword ptr [40B110], eax
  53. 00401188  |.  74 15                      |je      short 0040119F
  54. 0040118A  |.  FF75 08                    |push    dword ptr [ebp+8]                                  ; /Arg1
  55. 0040118D  |.  E8 D5150000                |call    00402767                                           ; \x.00402767
  56. 00401192  |.  59                         |pop     ecx
  57. 00401193  |.  85C0                       |test    eax, eax
  58. 00401195  |.  74 0F                      |je      short 004011A6
  59. 00401197  |.  8B75 08                    |mov     esi, dword ptr [ebp+8]
  60. 0040119A  |.^ E9 7BFFFFFF                \jmp     0040111A
  61. 0040119F  |>  E8 ED010000                call    00401391
  62. 004011A4  |.  8930                       mov     dword ptr [eax], esi
  63. 004011A6  |>  E8 E6010000                call    00401391
  64. 004011AB  |.  8930                       mov     dword ptr [eax], esi
  65. 004011AD  |>  5F                         pop     edi
  66. 004011AE  |.  8BC3                       mov     eax, ebx
  67. 004011B0  |.  5B                         pop     ebx
  68. 004011B1  |.  EB 14                      jmp     short 004011C7
  69. 004011B3  |>  56                         push    esi                                                 ; /Arg1
  70. 004011B4  |.  E8 AE150000                call    00402767                                            ; \x.00402767
  71. 004011B9  |.  59                         pop     ecx
  72. 004011BA  |.  E8 D2010000                call    00401391
  73. 004011BF  |.  C700 0C000000              mov     dword ptr [eax], 0C
  74. 004011C5  |.  33C0                       xor     eax, eax
  75. 004011C7  |>  5E                         pop     esi
  76. 004011C8  |.  5D                         pop     ebp
  77. 004011C9  \.  C3                         retn
复制代码

        这是 VC9 的 malloc() 函数的反汇编,可以看出,它依托的是 ntdll.RtlAllocateHeap()
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:28:46 | 显示全部楼层
jackz007 发表于 2022-11-26 17:24
这是 VC9 的 malloc() 函数的反汇编,可以看出,它依托的是 ntdll.RtlAllocateHeap()


是的,malloc要依托os的api来实现,但是malloc本身是一个C语言的库函数
malloc是C语言的库函数提供的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

请问你是怎么把turc装到bochs上面的,我比较好奇
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 17:46:29 | 显示全部楼层
桃花飞舞 发表于 2022-11-26 17:43
请问你是怎么把turc装到bochs上面的,我比较好奇

先在bochs里面安装一个ms-dos操作系统,然后在ms-dos操作系统里面安装tc
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 20:11:00 | 显示全部楼层
本帖最后由 竹逸 于 2022-11-26 20:14 编辑
人造人 发表于 2022-11-26 15:07
memset这个函数用来初始化一段内存空间

这是这个函数的声明,看到了吧,void * 类型的

  1. #include <stdio.h>
  2. #include <string.h>

  3. int main(void)
  4. {
  5.     int i, a[10] = {1000,15,2,2,2,2,2,2,2,2};
  6.     char *b;
  7.    
  8.     b = memset(a, 0, 1);
  9.    
  10.     for(i = 0 ; i < 10 ; i++)
  11.     {
  12.             printf("%d\n", *(b+i));
  13.         }
  14.         printf("--------------------------------\n");
  15.        
  16.     for(i = 0 ; i < 10 ; i++)
  17.     {
  18.             printf("%d\n", *(a+i));
  19.         }
  20.        
  21.     return 0;
  22. }
复制代码

下面这图说明了数据要如何输出完全按变量的指定类型来,变量b的类型是字符指针型,所以按字节输出,变量a的类型是整形数组,所以按int型输出,

1000的二进制是11 1110 1000,第一个字节清零,就变成了11 0000 0000


捕获.JPG
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 20:17:13 | 显示全部楼层
竹逸 发表于 2022-11-26 20:11
下面这图说明了数据要如何输出完全按变量的指定类型来,变量b的类型是字符指针型,所以按字节输出, ...

没看懂你想说什么
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-11-26 20:32:48 | 显示全部楼层
人造人 发表于 2022-11-26 20:17
没看懂你想说什么


我的意思大概就是说,把一块内存空间的起始地址赋值给字节型指针变量,那输出的数据是按字节逐个输出,如果把起始地址赋值给整形指针变量,那是按整形(4个字节)逐个输出,内存空间里存储的数据没有改变,改变的是输出的类型格式
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-11-26 20:43:00 | 显示全部楼层
竹逸 发表于 2022-11-26 20:32
我的意思大概就是说,把一块内存空间的起始地址赋值给字节型指针变量,那输出的数据是按字节逐个输出, ...

是的
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-23 14:42

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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