函数返回值
一般来说, 函数在返回的时候会将待返回的值存到eax(累加器)寄存器中, 然后再调用mov指令将eax中的值写到对应的变量中
接下来考虑有返回值的函数不写return语句的情况, 编写以下代码:
// test.c #include <stdio.h> int add(int a, int b) { int c = a + b; } int main() { int c = add(1, 1); printf("%d", c); // 你猜c是几, 对, 就是2 return 0; }
然后使用gcc编译为intel汇编代码
gcc -masm=intel -fverbose-asm -S -O0 test.c
编译出来的汇编代码如下(部分):
add: .LFB0: .cfi_startproc endbr64 push rbp # .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp #, .cfi_def_cfa_register 6 mov DWORD PTR -20[rbp], edi # a, a mov DWORD PTR -24[rbp], esi # b, b # return.c:4: int c = a + b; mov edx, DWORD PTR -20[rbp] # tmp87, a mov eax, DWORD PTR -24[rbp] # tmp88, b add eax, edx # tmp86, tmp87 # 计算edx+eax, 结果存在eax中 mov DWORD PTR -4[rbp], eax # c, tmp86 # return.c:5: } nop pop rbp # .cfi_def_cfa 7, 8 ret # 返回 .cfi_endproc main: .LFB1: .cfi_startproc endbr64 push rbp # .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp #, .cfi_def_cfa_register 6 sub rsp, 16 #, # return.c:8: int c = add(1, 1); mov esi, 1 #, mov edi, 1 #, call add # mov DWORD PTR -4[rbp], eax # c, tmp84 # 把eax的值存到c;里 # return.c:9: printf("%d", c); // 你猜c是几, 对, 就是2 mov eax, DWORD PTR -4[rbp] # tmp85, c mov esi, eax #, tmp85 lea rdi, .LC0[rip] #, mov eax, 0 #, call printf@PLT # # return.c:10: return 0; mov eax, 0 # _5, # return.c:11: } leave .cfi_def_cfa 7, 8 ret .cfi_endproc
可以看到, 在上面的代码中, 执行a+b后计算结果储存在eax中, 然后由于add这个函数里没写return语句, 自然eax的值就没有改变, 因此就传回了2
getc与fgetc的区别
f代表function, 因此fgetc是函数
getc是宏, 效率会更高但是可能会有副作用
考察以下代码:
FILE *files[10], *f = files; int i = 0; while (f < files + 10) { char = getc(*f++); }
在这段代码中f++可能会执行多次, 因此这种情况下应使用fgetc
gets与gets_s
gets()
函数不进行边界检查,从而此函数对缓冲区溢出攻击极度脆弱。无法安全使用它(除非程序运行的环境限定能出现在stdin
上的内容)。因此,此函数在 C99 的第三次勘误中被弃用,而在 C11 标准发布时被移除。推荐的替代品是fgets()
和gets_s()
。
绝对不要用gets()
。
也就是说gets在C11标准中已经被移除了, 只能使用fgets和gets_s
然而gets读入整行时会丢弃换行符, 而fgets不会, 为了读入整行, 我需要使用gets或gets_s
但是根据测试, 有些编译器似乎不支持gets_s