鱼C论坛

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

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

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

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

int main(void)
{
    int x = 123;
    printf("%d\n", sizeof(x));
    printf("%p\n", &x);
    func(&x);
    return 0;
}

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

使用道具 举报

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

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

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

int main(void) {
    char a = '0';
    int b = 123;
    double c = 123.456;
    printf("int: %zu\n", sizeof(int));
    printf("double: %zu\n", sizeof(double));
    printf("&a: %p\n", &a);
    printf("&b: %p\n", &b);
    printf("&c: %p\n", &c);
    return 0;
}
sh-5.1$ ./main
int: 4
double: 8
&a: 0x7fff48c90720
&b: 0x7fff48c90730
&c: 0x7fff48c90740
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 * 解引用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

    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.
在 GNU C 中,加法和减法运算在指向 void 的指针和指向函数的指针上受支持。这是通过将空隙或函数的大小视为 1 来完成的。这样做的结果是,在 void 和函数类型上也允许 sizeof,并返回 1。

https://www.cnblogs.com/hellogc/p/3374756.html
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

void_size.c: In function ‘int main(int, char**)’:
void_size.c:15: error: invalid application of ‘sizeof’ to a void type
void_size.c:16: error: ISO C++ forbids applying ‘sizeof’ to an expression of function type
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

        我喜欢用 g++  是因为更加严格的语法检查
想知道小甲鱼最近在做啥?请访问 -> 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 实现的。
想知道小甲鱼最近在做啥?请访问 -> 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语言的库函数
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

使用道具 举报

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

00401100  /$  8BFF                       mov     edi, edi                                            <--- malloc()
00401102  |.  55                         push    ebp
00401103  |.  8BEC                       mov     ebp, esp
00401105  |.  56                         push    esi
00401106  |.  8B75 08                    mov     esi, dword ptr [ebp+8]
00401109  |.  83FE E0                    cmp     esi, -20
0040110C  |.  0F87 A1000000              ja      004011B3
00401112  |.  53                         push    ebx
00401113  |.  57                         push    edi
00401114  |.  8B3D 08804000              mov     edi, dword ptr [<&KERNEL32.HeapAlloc>]              <--- edi = ntdll.RtlAllocateHeap
0040111A  |>  833D 6CAC4000 00           /cmp     dword ptr [40AC6C], 0
00401121  |.  75 18                      |jnz     short 0040113B
00401123  |.  E8 F7150000                |call    0040271F
00401128  |.  6A 1E                      |push    1E
0040112A  |.  E8 45140000                |call    00402574
0040112F  |.  68 FF000000                |push    0FF
00401134  |.  E8 87110000                |call    004022C0
00401139  |.  59                         |pop     ecx
0040113A  |.  59                         |pop     ecx
0040113B  |>  A1 F4B74000                |mov     eax, dword ptr [40B7F4]
00401140  |.  83F8 01                    |cmp     eax, 1
00401143  |.  75 0E                      |jnz     short 00401153
00401145  |.  85F6                       |test    esi, esi
00401147  |.  74 04                      |je      short 0040114D
00401149  |.  8BC6                       |mov     eax, esi
0040114B  |.  EB 03                      |jmp     short 00401150
0040114D  |>  33C0                       |xor     eax, eax
0040114F  |.  40                         |inc     eax
00401150  |>  50                         |push    eax
00401151  |.  EB 1C                      |jmp     short 0040116F
00401153  |>  83F8 03                    |cmp     eax, 3
00401156  |.  75 0B                      |jnz     short 00401163
00401158  |.  56                         |push    esi
00401159  |.  E8 53FFFFFF                |call    004010B1
0040115E  |.  59                         |pop     ecx
0040115F  |.  85C0                       |test    eax, eax
00401161  |.  75 16                      |jnz     short 00401179
00401163  |>  85F6                       |test    esi, esi
00401165  |.  75 01                      |jnz     short 00401168
00401167  |.  46                         |inc     esi
00401168  |>  83C6 0F                    |add     esi, 0F
0040116B  |.  83E6 F0                    |and     esi, FFFFFFF0
0040116E  |.  56                         |push    esi
0040116F  |>  6A 00                      |push    0
00401171  |.  FF35 6CAC4000              |push    dword ptr [40AC6C]
00401177  |.  FFD7                       |call    edi                                                 <--- 调用 ntdll.RtlAllocateHeap()
00401179  |>  8BD8                       |mov     ebx, eax
0040117B  |.  85DB                       |test    ebx, ebx
0040117D  |.  75 2E                      |jnz     short 004011AD
0040117F  |.  6A 0C                      |push    0C
00401181  |.  5E                         |pop     esi
00401182  |.  3905 10B14000              |cmp     dword ptr [40B110], eax
00401188  |.  74 15                      |je      short 0040119F
0040118A  |.  FF75 08                    |push    dword ptr [ebp+8]                                  ; /Arg1
0040118D  |.  E8 D5150000                |call    00402767                                           ; \x.00402767
00401192  |.  59                         |pop     ecx
00401193  |.  85C0                       |test    eax, eax
00401195  |.  74 0F                      |je      short 004011A6
00401197  |.  8B75 08                    |mov     esi, dword ptr [ebp+8]
0040119A  |.^ E9 7BFFFFFF                \jmp     0040111A
0040119F  |>  E8 ED010000                call    00401391
004011A4  |.  8930                       mov     dword ptr [eax], esi
004011A6  |>  E8 E6010000                call    00401391
004011AB  |.  8930                       mov     dword ptr [eax], esi
004011AD  |>  5F                         pop     edi
004011AE  |.  8BC3                       mov     eax, ebx
004011B0  |.  5B                         pop     ebx
004011B1  |.  EB 14                      jmp     short 004011C7
004011B3  |>  56                         push    esi                                                 ; /Arg1
004011B4  |.  E8 AE150000                call    00402767                                            ; \x.00402767
004011B9  |.  59                         pop     ecx
004011BA  |.  E8 D2010000                call    00401391
004011BF  |.  C700 0C000000              mov     dword ptr [eax], 0C
004011C5  |.  33C0                       xor     eax, eax
004011C7  |>  5E                         pop     esi
004011C8  |.  5D                         pop     ebp
004011C9  \.  C3                         retn
        这是 VC9 的 malloc() 函数的反汇编,可以看出,它依托的是 ntdll.RtlAllocateHeap()
想知道小甲鱼最近在做啥?请访问 -> 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语言的库函数提供的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

请问你是怎么把turc装到bochs上面的,我比较好奇
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

先在bochs里面安装一个ms-dos操作系统,然后在ms-dos操作系统里面安装tc
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

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

int main(void)
{
    int i, a[10] = {1000,15,2,2,2,2,2,2,2,2};
    char *b;
    
    b = memset(a, 0, 1);
    
    for(i = 0 ; i < 10 ; i++)
    {
            printf("%d\n", *(b+i));
        }
        printf("--------------------------------\n");
        
    for(i = 0 ; i < 10 ; i++)
    {
            printf("%d\n", *(a+i));
        }
        
    return 0;
}
下面这图说明了数据要如何输出完全按变量的指定类型来,变量b的类型是字符指针型,所以按字节输出,变量a的类型是整形数组,所以按int型输出,

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


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

使用道具 举报

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

没看懂你想说什么
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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


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

使用道具 举报

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

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-17 11:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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