読者です 読者をやめる 読者になる 読者になる

&&と||は何をやってるか調べてみた

C言語の"&&"と"||"は短絡評価をする演算子と知られています。実際には、どんな感じで評価しているか調べてみました。

// and_or.c
#include<stdio.h>
int and(int a, int b) {
	return a && b;
}
int or(int a, int b) {
	return a || b;
}
int main(void) {
  printf("1&&1=%d\n", and(1, 1));
  return 0;
}

"gcc -S and_or.c"でand_or.sを書いてもらいます。

	.file	"and_or.c"
	.text
	.globl	and
	.type	and, @function
and:
.LFB0:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	cmpl	$0, 8(%ebp)
	je	.L2
	cmpl	$0, 12(%ebp)
	je	.L2
	movl	$1, %eax
	jmp	.L3
.L2:
	movl	$0, %eax
.L3:
	popl	%ebp
	.cfi_def_cfa 4, 4
	.cfi_restore 5
	ret
	.cfi_endproc
.LFE0:
	.size	and, .-and
	.globl	or
	.type	or, @function
or:
.LFB1:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	cmpl	$0, 8(%ebp)
	jne	.L5
	cmpl	$0, 12(%ebp)
	je	.L6
.L5:
	movl	$1, %eax
	jmp	.L7
.L6:
	movl	$0, %eax
.L7:
	popl	%ebp
	.cfi_def_cfa 4, 4
	.cfi_restore 5
	ret
	.cfi_endproc
.LFE1:
	.size	or, .-or
	.section	.rodata
.LC0:
	.string	"1&&1=%d\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	andl	$-16, %esp
	subl	$16, %esp
	movl	$1, 4(%esp)
	movl	$1, (%esp)
	call	and
	movl	$.LC0, %edx
	movl	%eax, 4(%esp)
	movl	%edx, (%esp)
	call	printf
	movl	$0, %eax
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE2:
	.size	main, .-main
	.ident	"GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
	.section	.note.GNU-stack,"",@progbits

ふーん、なるほど、ようするに"&&"は

a && b 
1 a == 0 -> return 0
2 b == 0 -> return 0
3 return 1

な感じで、"||"は

a || b
1 a != 0 -> return 1
2 b == 0 -> return 0
3 return 1

といった感じというわけですね。