C语言进阶知识点(持续跟新)

来源:互联网 发布:伊思和兰芝哪个好 知乎 编辑:程序博客网 时间:2024/06/05 10:31

还是有点儿进阶的知识点,

1.大段、小段内存模型

        int val = 0x12345678;int *p1 = &val;char *p2 = (char *)p1;printf("%x\n",*p2);p2++;printf("%x\n",*p2);short *p3 = &val;printf("%x\n",*p3);p3 ++;printf("%x\n",*p3);    return 0;

运行结果:

78
56
5678

1234

结论:

(1)X86是小段(little endian),首先存储高位数值,然后依次向下存储。(与人类的思维不一样啊,反正记住,与读的顺序相反(读的意思是,我们从嘴巴读出来):先读的,后存储)

(2)再次印证了指针类型的重要性(不只是指针类型,在这里我还要说一句,其实在计算机内存中并不存在所谓的数据类型,比如char,int等的。这个类型在代码中的作用就是让编译器知道每次应该从那个地址起始读取多少位的数据,赋值给相应的变量

2  结构体大小和位域结构体大小的计算

http://www.cnblogs.com/leezhm/archive/2011/07/19/2110864.html

(1)结构体大小计算:

  a、结构体中的第一个成员的首地址也即是结构体变量的首地址。
  b、结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。
  c、结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n与结构体中最大数据类型的成员大小的最小值)的整数倍。

struct   {        char a;        int b;        short c;        char d;    }dataAlign;         struct    {        char a;        char d;        short c;        int b;          }dataAlign2;

第一个结果大小是12,第二个是8;

(2)位域的大小计算:

满足上面结构体计算的三个法则,除此之外,还要满足:

  d、如果相邻位域类型相同,并且它俩位域宽度之和小于它的数据类型大小,则后面的字段紧邻前面的字段存储。
  e、如果相邻位域类型相同,但是它俩位域宽度之和大于它的数据类型大小,则后面的字段将从新的存储单元开始,其偏移量为其类型的整数倍。
  f、如果相邻位域类型不同,在VC中是不采取压缩方式,但是GCC会采取压缩方式。

struct  {      char a:4;      int b:6;    }bitChar2;struct {    char a:3;    char b:3;    char c:7;    double d;    int e:4;    int f:30;  }bitChar;

第一个大小为8,第二个大小为24

3.常量字符串位于静态存储区

一道面试题引发的:

char* GetString1(){   char p[] = "Hello World";   return p;}char* GetString2(){   char *p = "Hello World";   return p;}int _tmain(int argc, _TCHAR* argv[]){   printf("GetString1 returns: %s. /n", GetString1());   printf("GetString2 returns: %s. /n", GetString2());   return 0;}

答案:输出两行,第一行GetString1 returns: 后面跟的是一串随机的内容,而第二行GetString2 returns: Hello World.两个函数的区别在于GetString1中是一个数组,而GetString2中是一个指针。

当运行到GetString1时,p是一个数组,会开辟一块内存,并拷贝"Hello World"初始化该数组。接着返回数组的首地址并退出该函数。由于p是GetString1内的一个局部变量,当运行到这个函数外面的时候,这个数组的内存会被释放掉。因此在_tmain函数里再去访问这个数组的内容时,结果是随机的。

当运行到GetString2时,p是一个指针,它指向的是字符串常量区的一个常量字符串。该常量字符串是一个全局的,并不会因为退出函数GetString2而被释放掉。因此在_tmain中仍然根据GetString2返回的地址得到字符串"Hello World"。

有关更多的内容见:

1:http://hi.baidu.com/%D0%C7%BB%F0%D3%C4%C0%B6/blog/item/410174384e529ffbb211c71c.html:常量字符串为什么在静态存储区?

2:http://blog.csdn.net/hackbuteer1/article/details/6706562:char str[]和char *str的区别

4. (int&)a和(int)a的区别

#include <iostream>#include <string>#include <cstdlib>using namespace std;int main(){float a = 1.0f;cout << (int)a << endl;cout << (int&)a << endl;cout << boolalpha << ( (int)a == (int&)a ) << endl; // 输出什么?float b = 0.0f;cout << (int)b << endl;cout << (int&)b << endl;cout << boolalpha << ( (int)b == (int&)b ) << endl; // 输出什么? }

(int&)a == static_cast <int&>(a)
(int)&a == reinterpret_cast <int>(&a);

(int&)a 不经过转换, 直接得到a在内存单元的值,并将其转换成整数输出。
(int)a a在内存中的值转换成int类型


float类型在内存中存储的形式是 ,符号位 指数 尾数
由754标准:阶码采用增码(该数补码的反符号),尾数采用原码
所以1.0f 在内存中的形式为
0011 1111 1000 0000 0000 0000 0000 0000
所以输出的是 0x3f800000

0 在内存中的的存储形式
0000 0000 0000 0000 0000 0000 0000 0000

所以输出的是0x00000000

所以前面一个是false,后面一个是true