根据stackoverflow的回答(https://stackoverflow.com/questions/15485179/how-to-check-if-c-string-is-empty),有若干种方法,我比较喜欢的是以下两种方式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int is_this_str_empty(char * str) {
if (strlen(str) == 0)
{
printf("\n Empty");
}
if (strcmp(str, ""))
{
printf("\n Empty");
}
}
第一种方式是判断字符串的长度,第二种方式判断字符串是否与空字符串相等。考虑执行效率,应该选用
strcmp()的方式,因为strlen()计算字符串长度时需要遍历字符串。
确实是这样的吗?我们看一下编译器编译出的汇编代码。
.LC0: .string "\n Empty"is_this_str_empty(char*): push rbx cmp BYTE PTR [rdi], 0 mov rbx, rdi je .L7.L2: cmp BYTE PTR [rbx], 0 jne .L8 pop rbx ret.L8: pop rbx mov edi, OFFSET FLAT:.LC0 xor eax, eax jmp printf.L7: mov edi, OFFSET FLAT:.LC0 xor eax, eax call printf jmp .L2
这里使用的是gcc 4.8.2(x86-64),启用-O3编译选项。可以看到编译器理解了strlen(str)==0就是判断字符串是空的意图,直接比较了第一个字符是否为空。我们再来看一下O0时的编译结果:
.LC0: .string "\n Empty"is_this_str_empty(char*): push rbp mov rbp, rsp sub rsp, 16 mov QWORD PTR [rbp-8], rdi mov rax, QWORD PTR [rbp-8] movzx eax, BYTE PTR [rax] test al, al jne .L2 mov edi, OFFSET FLAT:.LC0 mov eax, 0 call printf.L2: mov rax, QWORD PTR [rbp-8] movzx eax, BYTE PTR [rax] test al, al je .L4 mov edi, OFFSET FLAT:.LC0 mov eax, 0 call printf.L4: leave ret
与O3时差不多,直接比较了第一个字符是否为NULL.
为什么编译器可以对strlen()和strcmp()进行优化而不是调用库函数呢?这是因为strlen()和strcmp()都有编译器实现的builtin版本,编译器理解这些函数的意图,可以直接优化。
我们关闭编译器的builtin选项,可以看到:
.LC0: .string "\n Empty".LC1: .string ""is_this_str_empty(char*): push rbx mov rbx, rdi call strlen test rax, rax je .L7.L2: mov esi, OFFSET FLAT:.LC1 mov rdi, rbx call strcmp test eax, eax jne .L8 pop rbx ret.L8: pop rbx mov edi, OFFSET FLAT:.LC0 xor eax, eax jmp printf.L7: mov edi, OFFSET FLAT:.LC0 call printf jmp .L2
编译器直接调用了库函数,这时执行效率就不同了。
.LC0:
.string "\n Empty"
is_this_str_empty(char*):
push rbx
cmp BYTE PTR [rdi], 0
mov rbx, rdi
je .L7
.L2:
cmp BYTE PTR [rbx], 0
jne .L8
pop rbx
ret
.L8:
pop rbx
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
.L7:
mov edi, OFFSET FLAT:.LC0
xor eax, eax
call printf
jmp .L2
这里使用的是gcc 4.8.2(x86-64),启用-O3编译选项。可以看到编译器理解了strlen(str)==0就是判断
字符串是空的意图,直接比较了第一个字符是否为空。我们再来看一下O0时的编译结果:
.LC0:
.string "\n Empty"
is_this_str_empty(char*):
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
movzx eax, BYTE PTR [rax]
test al, al
jne .L2
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
.L2:
mov rax, QWORD PTR [rbp-8]
movzx eax, BYTE PTR [rax]
test al, al
je .L4
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
.L4:
leave
ret
与O3时差不多,直接比较了第一个字符是否为NULL.
为什么编译器可以对strlen()和strcmp()进行优化而不是调用库函数呢?这是因为strlen()和strcmp()
都有编译器实现的builtin版本,编译器理解这些函数的意图,可以直接优化。
我们关闭编译器的builtin选项,可以看到:
.LC0:
.string "\n Empty"
.LC1:
.string ""
is_this_str_empty(char*):
push rbx
mov rbx, rdi
call strlen
test rax, rax
je .L7
.L2:
mov esi, OFFSET FLAT:.LC1
mov rdi, rbx
call strcmp
test eax, eax
jne .L8
pop rbx
ret
.L8:
pop rbx
mov edi, OFFSET FLAT:.LC0
xor eax, eax
jmp printf
.L7:
mov edi, OFFSET FLAT:.LC0
call printf
jmp .L2
编译器直接调用了库函数,这时执行效率就不同了。