函数返回值
一般来说, 函数在返回的时候会将待返回的值存到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