竹逸 发表于 2022-11-26 13:29:18

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

本帖最后由 竹逸 于 2022-11-26 13:31 编辑

下面是我个人的理解,对吗?求大神解答以下{:5_92:}

因为malloc函数的返回值是无类型指针(无类型地址),即返回分配内存的起始地址,该地址上存储的数据是未定义类型的,所以该段空间属于字节型空间(计算机默认是以字节为单位),假如向该段空间的起始地址存储一个int型数据(int型数据是以4个字节为单位进行传输的)之后,再次读取该int型数据,由于该段空间的属于字节型空间,从起始地址开始读取出来的数据就只能是一个字节。强制类型转换是为了把这段字节型空间转换成以4个字节为单位的空间,这样往这段空间里存储int型数据或者读取都按照4个字节为单位进行传输的,就不会造成精度的损失。
我的猜测自己无法验证,因为malloc函数如果不进行强制转换就无法编译,也看不到内存的存储情况{:5_99:}

jackz007 发表于 2022-11-26 13:34:25

本帖最后由 jackz007 于 2022-11-26 13:39 编辑

      没有别的原因,只有等号两侧的数据类型匹配相容,编译器才能知道如何安排实现,也才能确定变量的使用规则。例如,同样是 p ++ ,如果是 (char *) p,p 的值将增加 1 ,如果是 (int *) p,p 的值将增加 4。

竹逸 发表于 2022-11-26 13:35:46

jackz007 发表于 2022-11-26 13:34
没有别的原因,只有等号两侧的数据类型匹配相容,编译器才能知道如何安排实现。

我发现不进行类型转换,可以用字符型指针来接收这段空间的起始地址,但int型指针就无法编译

int main(void)
{
        char *p;

        p = malloc(sizeof(int));
}

jackz007 发表于 2022-11-26 13:40:54

本帖最后由 jackz007 于 2022-11-26 13:44 编辑

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

         所以,我说过,等号两侧需要类型相容,指的就是这个意思。加了强制类型转换,代表你自己已经知道这样做所存在的风险,并需要坚持这样做,所以,编译器就不再拦着。

人造人 发表于 2022-11-26 13:58:02

先等一等,你的意思是这样的代码有问题?

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$

人造人 发表于 2022-11-26 13:59:33

知道为什么了吗?
为什么?

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 14:01:37

假如向该段空间的起始地址存储一个int型数据

怎么存?

竹逸 发表于 2022-11-26 14:01:40

jackz007 发表于 2022-11-26 13:40
所以,我说过,等号两侧需要类型相容,指的就是这个意思。加了强制类型转换,代表你自己已经 ...

我想起来了,数据要读取多大的长度好像是有栈顶寄存器(SP)来决定偏移多少个字节的,内存空间依然是字节型空间无法改变,改变的是由SP决定读取数据的长度{:5_109:}

人造人 发表于 2022-11-26 14:03:03

这么存?
sh-5.1$ cat main.c
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(32);
    *a = 1234;
    printf("%d\n", *a);
    free(a);
    return 0;
}
sh-5.1$ gcc -g -Wall -o main main.c
sh-5.1$ ./main
1234
sh-5.1$

人造人 发表于 2022-11-26 14:05:26

从起始地址开始读取出来的数据就只能是一个字节
上面的代码读取出来的就不是一个字节,是一个int,因为变量a的类型是int *

人造人 发表于 2022-11-26 14:07:14

简单来说就是,我没看懂你在说什么
如果你认为这个无法用C语言描述,那就用汇编语言来描述一下你的问题

竹逸 发表于 2022-11-26 14:10:50

人造人 发表于 2022-11-26 14:01
假如向该段空间的起始地址存储一个int型数据

怎么存?

依然是以字节存储的,只不过int型数据是占4个字节,就是要传输4个字节的数据,内存中的数据先是由CPU读取到通用寄存器里,要读取多大的长度由与它关联的寄存器给出,我想起了汇编的知识{:5_105:}

jackz007 发表于 2022-11-26 14:11:09

本帖最后由 jackz007 于 2022-11-26 14:12 编辑

竹逸 发表于 2022-11-26 14:01
我想起来了,数据要读取多大的长度好像是有栈顶寄存器(SP)来决定偏移多少个字节的,内存空间依然是字节 ...

       SP 是 16 位程序的栈顶指针,当需要局部变量存储空间的时候,需要多少字节,就把 SP 减掉多少,这样,堆栈操作(push / pop)就不会再使用这些空间,这里需要强调的是,堆栈空间只适合局部变量使用,malloc() 并不是从堆栈,而是从堆上获得的空间,所以,在函数内使用 malloc() 分配到的空间,并不会在函数退出的时候被收回,只要不使用 free() 进行释放,就会一直存在。
       再纠正一点,你读写存储空间的内容与 SP 并没有任何的直接关系。

人造人 发表于 2022-11-26 14:21:18

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

malloc函数申请的内存空间需要进行类型强制转换?
反正我写代码是从来不强制转换的,因为没有必要,因为强制转换既不会增加代码的可读性,也不会增加代码的执行效率,完全就是多余的,就和auto关键字差不多,我见你写代码从来不在变量前面加这个,我也不加,因为没有必要
强制转换也差不多就是这样的,因为没有必要,当然就算是加上也不会有语法错误,只是没有必要

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$


再举个例子?
在C++中,类里面可以不加this直接使用类内部的变量,但是这里我会选择加上
这里
      return x + y;
      return this->x + this->y;
这两个都是可以的,但是这里我会选择加上
因为我认为这样会增加代码的可读性,这完全就是我自己的感觉


其实有些东西就是多余的,完全没有必要的,要不要用,完全取决于你自己

class test_t {
public:
    test_t(int x = 0, int y = 0): x(x), y(y) {}
    int add() {
      //return x + y;
      return this->x + this->y;
    }
private:
    int x, y;
};

竹逸 发表于 2022-11-26 14:21:26

jackz007 发表于 2022-11-26 14:11
SP 是 16 位程序的栈顶指针,当需要局部变量存储空间的时候,需要多少字节,就把 SP 减掉多少, ...

是的,我学汇编的时候就是小甲鱼8086的CPU知识,所以也就只能用8086的来描述,而且malloc函数却是也是从堆中开辟的空间,就是不知道堆指针是由什么寄存器来作偏移量的{:5_99:}

人造人 发表于 2022-11-26 14:22:31

竹逸 发表于 2022-11-26 14:10
依然是以字节存储的,只不过int型数据是占4个字节,就是要传输4个字节的数据,内存中的数据先是由CPU读取 ...

11楼
https://fishc.com.cn/forum.php?mod=redirect&goto=findpost&ptid=221281&pid=6063279

人造人 发表于 2022-11-26 14:23:38

竹逸 发表于 2022-11-26 14:10
依然是以字节存储的,只不过int型数据是占4个字节,就是要传输4个字节的数据,内存中的数据先是由CPU读取 ...

先把我的回复从上到下看一遍,然后再提出你的问题

竹逸 发表于 2022-11-26 14:26:54

本帖最后由 竹逸 于 2022-11-26 14:28 编辑

人造人 发表于 2022-11-26 14:03
这么存?

好神奇,为什么我问问题之前,和你同样的代码无法编译,现在又能编译了{:5_107:}你看我问题描述,描述说不进行强制转换就无法编译,为啥现在又能编译了

jackz007 发表于 2022-11-26 14:28:47

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

      你不用关心堆指针的事情,因为,这个完全是由操作系统在掌控(malloc() 是 Windows API),你只需要按规则进行申请、使用和释放就可以了。

人造人 发表于 2022-11-26 14:32:27

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

17楼
https://fishc.com.cn/forum.php?mod=redirect&goto=findpost&ptid=221281&pid=6063298
页: [1] 2 3
查看完整版本: malloc函数申请的内存空间为什么要进行类型强制转换?