[关闭]
@nrailgun 2015-10-01T15:51:21.000000Z 字数 1913 阅读 1593

C 返回值截断问题

程序设计


现在有代码一份,请猜测输出?

  1. // file: main.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. unsigned char nr_sum(unsigned char a[], int len)
  5. {
  6. int i, sum = 0;
  7. for (i = 0; i < len; i++) {
  8. sum += a[i];
  9. }
  10. return sum;
  11. }
  12. int main(int argc, char *argv[])
  13. {
  14. unsigned char ucs[] = {
  15. 5, -5
  16. };
  17. int rv = nr_sum(ucs, 2);
  18. printf("%d\n", rv);
  19. return EXIT_SUCCESS;
  20. }

档案很简单,明显是 0,毫无亮点。

另一份代码:

  1. // file: math.c
  2. #include <stdio.h>
  3. unsigned char nr_sum(unsigned char a[], int len)
  4. {
  5. int i, sum = 0;
  6. for (i = 0; i < len; i++) {
  7. sum += a[i];
  8. }
  9. return sum;
  10. }
  1. // file: main.c
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main(int argc, char *argv[])
  5. {
  6. unsigned char ucs[] = {
  7. 5, -5
  8. };
  9. int rv = nr_sum(ucs, 2);
  10. printf("%d\n", rv);
  11. return EXIT_SUCCESS;
  12. }

欢迎猜答案!只是简单把函数换一个地方放而已呀,并无大碍。答案是 0..., 就有鬼了....答案是 256~

为了向后兼容,C 没有禁止 implicit declaration,而对于那些没有 declaration 的函数,C 默认返回是 int。第一份代码由于写在同一个文件,不需要声明,没发生问题。第二个文件,忘记声明,假设返回 int。结果倒霉的函数真的返回的是 int,所以没有被(如同我期望般)截断。

检查生成的汇编:

  1. .file "math.c"
  2. .section .rodata
  3. .LC0:
  4. .string "nr_sum %d\n"
  5. .text
  6. .globl nr_sum
  7. .type nr_sum, @function
  8. nr_sum:
  9. .LFB0:
  10. .cfi_startproc
  11. pushq %rbp
  12. .cfi_def_cfa_offset 16
  13. .cfi_offset 6, -16
  14. movq %rsp, %rbp
  15. .cfi_def_cfa_register 6
  16. subq $32, %rsp
  17. movq %rdi, -24(%rbp)
  18. movl %esi, -28(%rbp)
  19. movl $0, -4(%rbp)
  20. movl $0, -8(%rbp)
  21. jmp .L2
  22. .L3:
  23. movl -8(%rbp), %eax
  24. movslq %eax, %rdx
  25. movq -24(%rbp), %rax
  26. addq %rdx, %rax
  27. movzbl (%rax), %eax
  28. movzbl %al, %eax
  29. addl %eax, -4(%rbp)
  30. addl $1, -8(%rbp)
  31. .L2:
  32. movl -8(%rbp), %eax
  33. cmpl -28(%rbp), %eax
  34. jl .L3
  35. movl -4(%rbp), %eax
  36. movl %eax, %esi
  37. movl $.LC0, %edi
  38. movl $0, %eax
  39. call printf
  40. movl -4(%rbp), %eax
  41. leave
  42. .cfi_def_cfa 7, 8
  43. ret
  44. .cfi_endproc
  45. .LFE0:
  46. .size nr_sum, .-nr_sum
  47. .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
  48. .section .note.GNU-stack,"",@progbits

movl -4(%rbp), %eax 返回值放在 32 bit 长度的寄存器里面,没有截断就回传。这是真的坑爹。

顺便贴一下出问题的代码:

  1. static
  2. mp_fp_struct_t *mp_lookup_fp_struct_at(uint32_t phys, size_t len)
  3. {
  4. uint8_t *a, *end, *p;
  5. int rv;
  6. a = p2v(phys);
  7. end = a + len;
  8. for (p = a; p < end; p += sizeof(mp_fp_struct_t)) {
  9. if (!memcmp(p, "_MP_", 4)) {
  10. rv = sum_uc(p, sizeof(mp_fp_struct_t));
  11. printf("return value %d\n", rv);
  12. if (!rv)
  13. return (mp_fp_struct_t *) p;
  14. }
  15. }
  16. return NULL;
  17. }

我不幸地忘记 include sum_uc 所在的头文件了。所以 sum_uc 总是返回 int.... 经过被坑了一个晚上的惨痛经历,我决定打开警告选项:

  1. gcc -Wall kernel/mp.c
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注