Chinaunix首页 | 论坛 | 博客
  • 博客访问: 463261
  • 博文数量: 56
  • 博客积分: 517
  • 博客等级: 下士
  • 技术积分: 751
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-12 18:16
文章分类

全部博文(56)

文章存档

2015年(2)

2014年(6)

2013年(29)

2012年(17)

2011年(2)

分类: C/C++

2014-11-08 19:22:44

本篇作为一个引子,领着大家梳理c语言中难点或容易忽视的知识点,知识点以专题形式展开。

专题一 结构占用内存长度
在linux/windows上运行下面一段程序,你能总结出struct内存对齐规则吗?

点击(此处)折叠或打开

  1. struct ta {
  2. short b;
  3.         long a;
  4.         char c;
  5. };


  6. struct tb {
  7. short b;
  8.         int a;
  9.         char c;
  10. };


  11. struct tc {
  12.         short a;
  13.         char b;
  14.         short c;
  15.         };


  16. printf("size ta:%d tb:%d tc:%d\n", sizeof(struct ta), sizeof(struct tb), sizeof(struct tc));

参考分析:struct内存总是以其L最长内存占字节成员a为基准来对齐的,如果a后面相邻成员所占内存字节和小于或等于nL(n为正整数)则内存拼接,
其中sizeof(long)结果取决于操作系统和cpu结构,各操作系统和cpu架构下sizeof(long)如下表:
 OS           arch           size
Windows       IA-32        4 bytes
Windows       Intel 64     4 bytes
Windows       IA-64        4 bytes
Linux         IA-32        4 bytes
Linux         Intel 64     8 bytes
Linux         IA-64        8 bytes
Mac OS X      IA-32        4 bytes
Mac OS X      Intel 64     8 bytes  
(详见:)


假设改程序运行于Linux IA-64上则结果为:
size ta:24 tb:12 tc:6


专题二 指针和数组
运行下面程序,观察数组array地址&array输出结果,另外观察程序中指针的声明,你能学到什么?

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. int g_array[] = {2,3,4,5,6,7,8,9, 10};

  3. int func1(int a)
  4. {
  5. printf("%s be called\n", __func__);
  6. return a;
  7. }


  8. int func2(int a)
  9. {
  10. printf("%s be called\n", __func__);
  11. return a;
  12. }


  13. int (*func3(int array[4]))[9]
  14. {
  15. int (*r)[9] = &g_array;
  16. return r;
  17. }


  18. char *const *func4()
  19. {
  20.         char *const str = "abc";
  21.         char *const *p = &str;
  22.         return p;
  23. }


  24. void addr1(int array[])
  25. {
  26. /*此处array被编译器转化为指针,array和&array不再相等,结果为&array[1] - 4 == &array[0] == array != &array*/
  27. printf("%x %x %x %x\n", array, &array, &array[0], &array[1]);
  28. }


  29. void addr2(int *array)
  30. {
  31. /*此行代码在gcc和llvm上的结果不同*/
  32. printf("%x %x %x %x %x\n", array, &array, &array[0], &array[1], ++array);
  33. }


  34. int main()
  35. {

  36. int array[4] = {1, 2, 3, 4};
  37. int( *p)[4] = &array;
  38. int (*pfunc[])(int) = {func1, func2};
  39. printf("%d, %d, %d\n", (*p)[1], pfunc[1](3), (*func3(array))[1]);

  40. addr1(array);
  41. addr2(array);
  42. printf("%#x %#x %#x %#x\n", array, &array, &array[0], &array[1]);
  43. addr1(g_array);
  44. addr2(g_array);


  45. printf("%#x %#x %#x %#x\n", g_array, &g_array, &g_array[0], &g_array[1]);
  46. char * const *(*next)() = func4;

  47. return 0;
  48. }

参考分析:
gcc编译器输出:
func2 be called
2, 3, 3
bfe69a68 bfe69a40 bfe69a68 bfe69a6c
bfe69a6c bfe69a40 bfe69a6c bfe69a70 bfe69a6c
0xbfe69a68 0xbfe69a68 0xbfe69a68 0xbfe69a6c
80498c0 bfe69a40 80498c0 80498c4
80498c4 bfe69a40 80498c4 80498c8 80498c4
0x80498c0 0x80498c0 0x80498c0 0x80498c4

llvm编译器输出:
func2 be called
2, 3, 3
5e72ebf0 5e72eb88 5e72ebf0 5e72ebf4
5e72ebf0 5e72eb88 5e72ebf0 5e72ebf4 5e72ebf4
0x5e72ebf0 0x5e72ebf0 0x5e72ebf0 0x5e72ebf4
14d2040 5e72eb88 14d2040 14d2044
14d2040 5e72eb88 14d2040 14d2044 14d2044
0x14d2040 0x14d2040 0x14d2040 0x14d2044
gcc、llvm对printf("%x %x %x %x %x\n", array, &array, &array[0], &array[1], ++array);这行处理不同,
你观察到了吧,另外还有四个有趣的问题:
1.addr1、addr2中array!= &array,main函数中array == &array。
(数组作为函数参数在函数内被转化为指向数组首地址的指针,对指针取地址就是另外的值了)
2.gcc运行这行(++array后),&array却没有变。
3.func2 be called却最先打印。
4.函数中涉及到的指针

点击(此处)折叠或打开

  1. int (*pfunc[])(int)//指向函数数组的指针
  2. int (*func3(int array[4]))[9]//函数指针,其形参为int [4], 返回长度为9的int指针向量(等价于int [][9]
  3. int( *p)[4];//长度为4的int指针向量,可以这么使用,
  4. int a[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}};
  5. int (*p)[4] = a;
  6. printf("%d, %d, %d\n", p[0][1], (*p)[1], (*(p + 1))[1]);//结果:2, 2, 6

专题三 switch - case容易忽视的细节
下面这段程序结果是什么?

点击(此处)折叠或打开

  1. int main()
  2. {
  3.         int i = 1, a = 0;
  4.         switch (i) {
  5.                 a = 1;
  6.                 case 0:
  7.                         printf("0\n");
  8.                 break;
  9.                 case 1:
  10.                         printf("1\n");
  11.                 default:
  12.                         break;
  13.         }


  14.         printf("a:%d\n", a);
  15.         return 0;
  16. }
参考分析:
编译器忽略switch和case之间的语句,故答案为:0

专题四 typedef用法要诀
初识typedef你是否不知所云,那么请往下看。
语法:typedef 变量声明
变量名字即代表所声明的类型,例如,typedef char T[2], T t[3]为一个3行2列的二维数组,
又如,

点击(此处)折叠或打开

  1. typedef struct student{
  2. int id;
  3. int age;
  4. char sex;
  5. char name[32];
  6. } student_t;
student_t zhangsan;等价于 struct student{...} zhangsan;      
阅读(1521) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~