竹逸 发表于 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;
}

人造人 发表于 2022-11-26 16:34:16

竹逸 发表于 2022-11-26 16:11


报错说 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 * 解引用

人造人 发表于 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

人造人 发表于 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


jackz007 发表于 2022-11-26 17:12:26

人造人 发表于 2022-11-26 16:10
因为你使用的g++,这是C++编译器
gcc才是C语言编译器

      我喜欢用 g++是因为更加严格的语法检查

jackz007 发表于 2022-11-26 17:14:00

人造人 发表于 2022-11-26 16:09
malloc() 是 Windows API

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


         这一点你无须有任何的质疑,因为我是一个 Cracker,malloc() 的功能一定是依托 OS 的 API 实现的。

人造人 发表于 2022-11-26 17:18:06

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

对的,malloc要依托os的api来实现,但是malloc本身不是os的api
malloc本身是一个C语言的库函数

人造人 发表于 2022-11-26 17:24:25

jackz007 发表于 2022-11-26 17:12
我喜欢用 g++是因为更加严格的语法检查

是的,C++检查的更严格,但是你演示的内容是错误的
C语言允许 void *可以隐式转换到任何其他指针类型,任何其他指针类型也可以隐式转换到 void *
C语言允许这样的代码 int *p = malloc(4);
但是你演示的内容的结果是这是错误的代码

jackz007 发表于 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
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 , 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
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
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 , eax
00401188|.74 15                      |je      short 0040119F
0040118A|.FF75 08                  |push    dword ptr                                   ; /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
0040119A|.^ E9 7BFFFFFF                \jmp   0040111A
0040119F|>E8 ED010000                call    00401391
004011A4|.8930                     mov   dword ptr , esi
004011A6|>E8 E6010000                call    00401391
004011AB|.8930                     mov   dword ptr , 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 , 0C
004011C5|.33C0                     xor   eax, eax
004011C7|>5E                         pop   esi
004011C8|.5D                         pop   ebp
004011C9\.C3                         retn
      这是 VC9 的 malloc() 函数的反汇编,可以看出,它依托的是 ntdll.RtlAllocateHeap()

人造人 发表于 2022-11-26 17:28:46

jackz007 发表于 2022-11-26 17:24
这是 VC9 的 malloc() 函数的反汇编,可以看出,它依托的是 ntdll.RtlAllocateHeap()

是的,malloc要依托os的api来实现,但是malloc本身是一个C语言的库函数
malloc是C语言的库函数提供的

桃花飞舞 发表于 2022-11-26 17:43:07

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

请问你是怎么把turc装到bochs上面的,我比较好奇

人造人 发表于 2022-11-26 17:46:29

桃花飞舞 发表于 2022-11-26 17:43
请问你是怎么把turc装到bochs上面的,我比较好奇

先在bochs里面安装一个ms-dos操作系统,然后在ms-dos操作系统里面安装tc

竹逸 发表于 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 = {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


人造人 发表于 2022-11-26 20:17:13

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

没看懂你想说什么

竹逸 发表于 2022-11-26 20:32:48

人造人 发表于 2022-11-26 20:17
没看懂你想说什么

我的意思大概就是说,把一块内存空间的起始地址赋值给字节型指针变量,那输出的数据是按字节逐个输出,如果把起始地址赋值给整形指针变量,那是按整形(4个字节)逐个输出,内存空间里存储的数据没有改变,改变的是输出的类型格式

人造人 发表于 2022-11-26 20:43:00

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

是的
页: 1 2 [3]
查看完整版本: malloc函数申请的内存空间为什么要进行类型强制转换?