Forwarded from dnaugsuz
指针一直以来不是最高大上的概念啊,稍微对现代电子计算机存储器结构、冯诺伊曼计算机结构有点感觉的人都会觉得指针实际上非常符合直觉
因为内存就是一大打能够以某种最小粒度(很多时候是
然后 C 只要不弄出悬垂指针、空指针也是最吼滴,对新手最大的问题可能是动态内存分配和“为什么我不能返回一个本地变量
然后 C 的
在编程语言理论里,
当
(当然这个函数也可以用 C11 的新特性
然后那个
要是刻意指定可以写
因为内存就是一大打能够以某种最小粒度(很多时候是
char,一个字节)访问(读写)存储器的集合而已,只要你知道可随机访问的存储器一般以某种(整型数值上)连续的方式编址可访问就好了然后 C 只要不弄出悬垂指针、空指针也是最吼滴,对新手最大的问题可能是动态内存分配和“为什么我不能返回一个本地变量
char *a”?(他们实际上看不到运行时有个叫做栈(stack) 的东西.... 也不知道有 GC, garbage collector 编程语言里所谓的对象在 C 里都是必须弄明白他们到底应该被『存储』在哪里的,要不然下面的机器没办法执行)然后 C 的
struct, union, array 什么的内存布局也没有那么奇怪,也提供了 &* 直接对其他对象取地址的方式,不会指针运算双重指针(int **)也总是会的吧。void swap(int *a, int *b) {
auto int saved_a = *a;
*a = *b;
*b = saved_a;
}
注意这里 * 有两种含义:在编程语言理论里,
int* 类型的东西是可以同时作为左值 (lhs, {get;set;}) 和右值 (rhs {get;}) 使用的(而 const int* 就不可以,只能当左值取值不能赋值)当
*a 出现在需要左值的位置时,* 操作符的语义实际上是『“ptr write”』给指针赋值,比如 *a=-1;
反之,它的含义是解指针(ptr read)比如上面的 *a = *b;等号右边
*b 就是 deref 操作。(当然这个函数也可以用 C11 的新特性
_Generic 写,不过这里是作为示范就先不写)然后那个
auto 是存储位置的修饰符,这个是默认的,表示不刻意指定要是刻意指定可以写
register 机器寄存器、static 常量(一般存在 ELF 的 .bss, block started by symbol 端)、extern 外部编译单元可见等等Forwarded from dnaugsuz
KN 不是基于 JVM 的,对于 executable 它翻译到 LLVM 表示后就直接发射机器码了,但是你可以注意到 KN 也提供 GC
KN 远比 JVM 上的 Kotlin 提供的底层控制多,比如它好像还可以给本地栈指定什么参数?
runtime/src/main/cpp/Memory.h
111: 00000000002288c0 5 FUNC GLOBAL DEFAULT 15 Kotlin_createRuntime
(注意这不是 java.lang.Runtime)
我上次写的没有用到动态内存管理,但是 KN 是有 runtime 的,它不像 Rust 的 runtime 很小,而且甚至可以去掉,毕竟是要和 JVM/JS 版兼容的
KN 远比 JVM 上的 Kotlin 提供的底层控制多,比如它好像还可以给本地栈指定什么参数?
runtime/src/main/cpp/Memory.h
readelf -s ./build/bin/linuxX64/releaseExecutable/secure-desktop.kexe|grep Kotlin102: 00000000002289b0 146 FUNC GLOBAL DEFAULT 15 Kotlin_destroyRuntime
111: 00000000002288c0 5 FUNC GLOBAL DEFAULT 15 Kotlin_createRuntime
(注意这不是 java.lang.Runtime)
我上次写的没有用到动态内存管理,但是 KN 是有 runtime 的,它不像 Rust 的 runtime 很小,而且甚至可以去掉,毕竟是要和 JVM/JS 版兼容的
GitHub
JetBrains/kotlin-native
Kotlin/Native infrastructure. Contribute to JetBrains/kotlin-native development by creating an account on GitHub.
Forwarded from Richard Yu
因为不是C/C++,谁知道有没有指针?没的话那就传个0吧。C++我会写nullptr。
Forwarded from dnaugsuz
如果没有指针类型的话也是可能的,但是,如果是我也会搞个全局的常量
如果类型系统菜,程序员负责给它洗地
nullptr, 尽可能避免混淆如果类型系统菜,程序员负责给它洗地
Forwarded from dnaugsuz
是啊,所以我说是一个常量
const char *EMPTY_CHARP = "";
这里我没有指定具体分配位置,但它是常量,换句话说编译器喜欢内联也可以直接翻译成GetModuleHandle("");
或者const static char EMPTY_CHARP[] = {'\0'};
然后 GetModuleHandle(EMPTY_CHARP);
Forwarded from dnaugsuz
printf(EMPTY_CHARP); 的 x86 翻译结果是mov rdi, qword ptr [EMPTY_CHARP]
mov dword ptr [rbp - 4], eax # 4-byte Spill
mov al, 0
call printf
xor ecx, ecx
mov dword ptr [rbp - 8], eax # 4-byte Spill
上面一句 printf(""); 是movabs rdi, offset .L.str
mov al, 0
call printf
似乎和 printf(0); 是有区别的mov al, 0
call printfForwarded from Richard Yu
我说的是 GetModuleHandle 的情况啊,上面的情况是要传0进去。
Forwarded from dnaugsuz
😵 那我就完全糊涂了... 总之我上面的情况你支持吧?
之前的 GetModuleHandle 的处理,反正我不是 Win32 的程序员,算了吧
之前的 GetModuleHandle 的处理,反正我不是 Win32 的程序员,算了吧
Forwarded from dnaugsuz
也没有,你想想
上面那条
你用 x86 作为目标机器再编译一遍就会发现都是用机器栈传参数的
sizeof(char *) 是 4上面那条
call printf 指令是跳转子程序mov dword ptr [rbp - 4], eax
你知道这是赋值第二个参数(vararg)就可以了,前面 eax 的值肯定是 0 (xor eax, eax)mov rdi, qword ptr [EMPTY_CHARP]
使用 rdi 寄存器传递是因为这是 x86_64 (long mode 支持)你用 x86 作为目标机器再编译一遍就会发现都是用机器栈传参数的
Forwarded from dnaugsuz
我之前是说有人觉得
等等我理解你的意思了,原来
"" 不优雅的情况,就不用 nullptr 替换了....等等我理解你的意思了,原来
nullptr 的确和 "" 是不一样的... 但我之前没有说他们一样啊...