竹逸
发表于 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
我的意思大概就是说,把一块内存空间的起始地址赋值给字节型指针变量,那输出的数据是按字节逐个输出, ...
是的