代码改变世界

[置顶]C++随记总结(1)----关于C++中的大小端、位段(惑位域)和内存对齐

2011-07-19 17:33 by libiver, 阅读(6024) 阅读, 推荐(7) 推荐, 收藏,

         

声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。

本文链接:http://www.cnblogs.com/leezhm/archive/2011/07/19/2110864.html

开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog

 

          听到好几个朋友说到去一些公司做面试,总是遇到关于大小端、位段(或者叫位域)和内存对齐的考题,然后就不知所措了。虽然我认为很多开发根本就用不到这个,但是我认为很有必要学习理解这些知识点,因为它可以让你更了解C++的,了解程序在内存的运行情况,也能加深对计算机系统的理解。

        声明:由于本文的代码会受到计算机环境的影响,故在此说明本篇博文中的程序的运行环境。

         1、Microsoft Windows 7 Ultimate Edition Service Pack 1 (64bit  6.1.7601)

         2、Microsoft Visual Studio 2010 Version 10.0.40219.1 SP1Rel(Ultimate--ENU)。

         3、Microsoft .NET Framework Version 4.0.30319 SP1Rel

         4、Microsoft Visual C++ 2010

         注:虽然系统是64位的,但是我是使用VC++ 2010默认配置,也即是x86平台。所以下面所有示例和文字表述都是基于32位编译平台。

一、大小端

          在现代“冯.诺依曼体系结构”计算机中,它的数制都是采用二进制来存储,并且是以8位,一个字节为单位,产生内存地址系统。数据在内存中有如下三种存在方式:

           1、从静态存储区分配:此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储。

           2、在栈区分配:在程序的相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率

                                               高,但容量有限。

            3、在堆区分配:动态分配内存。用new/malloc时开辟,delete/free时释放。变量的生存期由用户指定,灵活,但会有内存泄露等问题。

           对于像C++中的char这样的数据类型,它本身就是占用一个字节的大小,不会产生什么问题。但是当数制类型为int,在32bit的系统中,它需要占用4个字节(32bit),这个时候就会产生这4个字节在寄存器中的存放顺序的问题。比如int maxHeight = 0x12345678,&maxHeight = 0x0042ffc4。具体的该怎么存放呢?这个时候就需要理解计算机的大小端的原理了。

          大端:(Big-Endian)就是把数值的高位字节放在内存的低位地址上,把数值的地位字节放在内存的高位地址上。

          小端:(Little-Endian)就是把数字的高位字节放在高位的地址上,低位字节放在低位地址上。

          我们常用的x86结构都是小端模式,而大部分DSP,ARM也是小端模式,不过有些ARM是可以选择大小端模式。所以对于上面的maxHeight是应该以小端模式来存放,具体情况请看下面两表。

    地址 0x0042ffc4 0x0042ffc5 0x0042ffc6 0x0042ffc7

数值

0x78

0x56

0x34

0x12

                                                                                                                                     上图为小端模式
地址 0x0042ffc4 0x0042ffc5 0x0042ffc6 0x0042ffc7
数值

0x12

0x34

0x56

0x78

上图为大端模式

         通过上面的表格,可以看出来大小端的不同,在这里无法讨论那种方式更好,个人觉得似乎大端模式更符合我的习惯。注:在这里我还要说一句,其实在计算机内存中并不存在所谓的数据类型,比如char,int等的。这个类型在代码中的作用就是让编译器知道每次应该从那个地址起始读取多少位的数据,赋值给相应的变量。)

二、位段或位域

         在前面已经提起过,在计算机中是采用二进制01来表示数据的,每一个0或者1占用1位(bit)存储空间,8位组成一个字节(byte),为计算机中数据类型的最小单位,如char在32bit系统中占用一个字节。但是正如我们知道的,有时候程序中的数据可能并不需要这么的字节,比如一个开关的状态,只有开和关,用10分别替代就可以表示。此时开关的状态只需要一位存储空间就可以满足要求。如果用一个字节来存储,显然浪费了另外的7位存储空间。所以在C语言中就有了位段(有的也叫位域,其实是一个东西)这个概念。具体的语法就是在变量名字后面,加上冒号(:)和指定的存储空间的位数。具体的定义语法如下:

   1:  struct 位段名称  
   2:  {    
   3:       位段数据类型   位段变量名称 : 位段长度,      
   4:        .......   
   5:   }
   6:   
   7:  实例
   8:   
   9:  struct Node
  10:  {
  11:     char a:2;
  12:     double i;
  13:     int c:4;
  14:  }node;
 

    其实定义很简单,上面示例的意义是,定义一个char变量a,占用2位存储空间,一个double变量i,以及一个占用4位存储的int变量c。请注意这里改变了变量本来占用字节的大小,并不是我们常规定义的一个int变量占用4个字节,一个char变量占用1一个字节。但是sizeof(node) = ?呢,在实际的运行环境中运行,得到sizeof(node) = 24;为什么呢?说起来其实也很简单,字节对齐,什么是字节对齐,待会下一个段落会具体讲解。先来看一个面试示例,代码如下:

   1:  #include <iostream>
   2:   
   3:  using namespace std;
   4:   
   5:  union
   6:  {
   7:      struct
   8:      {
   9:          char i:1;
  10:          char j:2;
  11:          char m:3;
  12:      }s;
  13:   
  14:      char ch;
  15:  }r;
  16:   
  17:  int _tmain(int argc, _TCHAR* argv[])
  18:  {
  19:      r.s.i = 1;
  20:      r.s.j = 2;
  21:      r.s.m = 3;
  22:   
  23:      cout<<" r.ch = "<<(int)r.ch<<" = 0x"<<hex<<(int)r.ch<<endl
  24:          <<" sizeof(r) = "<<sizeof(r)<<endl;
  25:   
  26:      return 0;
  27:  }

           好了,具体结果是怎么样的呢?

     r.ch = 29 = 0x1d
     sizeof(r) = 1
 
           为什么是这个结果?说起来其实也很简单,结合前面的大小端,可以具体来分析下,先看下表:

 

      m:3

j:2

i:1

7

6

5

4

3

2

1

0

0

0

0

1

1

1

0

1

1

D

          上面的表格,解释了为什么这里等于29=0x1D。首先i、j、m分别占用1、2、3位,分布在一个字节中。故根据赋值语句可知,在内存的相应的字节上首先存储i=1,然后存储j=2,也即10,而后是m=3,也即011。可看上表的不同颜色所示,然后不足的位,补0来填充。所以整个字节就是0x1D=29,顾r.ch = 29 = 0x1D。

         关于位段,补充以下规则:

三、内存对齐

          内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 。

          为什么需要内存对齐?对齐有什么好处?是我们程序员来手动做内存对齐呢?还是编译器在进行自动优化的时候完成这项工作?

          在现代计算机体系中,每次读写内存中数据,都是按字(word,4个字节,对于X86架构,系统是32位,数据总线和地址总线的宽度都是32位,所以最大的寻址空间为232 = 4GB(也许有人会问,我的32位XP用不了4GB内存,关于这个不在本篇博文讨论范围),按A[31,30…2,1,0]这样排列,但是请注意为了CPU每次读写4个字节寻址,A[0]和A[1]两位是不参与寻址计算的。)为一个快(chunks)来操作(而对于X64则是8个字节为一个快)。注意,这里说的CPU每次读取的规则,并不是变量在内存中地址对齐规则。既然是这样的,如果变量在内存中存储的时候也按照这样的对齐规则,就可以加快CPU读写内存的速度,当然也就提高了整个程序的性能,并且性能提升是客观,虽然当今的CPU的处理数据速度(是指逻辑运算等,不包括取址)远比内存访问的速度快,程序的执行速度的瓶颈往往不是CPU的处理速度不够,而是内存访问的延迟,虽然当今CPU中加入了高速缓存用来掩盖内存访问的延迟,但是如果高密集的内存访问,一种延迟是无可避免的,内存地址对齐会给程序带来了很大的性能提升。

          内存地址对齐是计算机语言自动进行的,也即是编译器所做的工作。但这不意味着我们程序员不需要做任何事情,因为如果我们能够遵循某些规则,可以让编译器做得更好,比较编译器不是万能的。

          为了更好理解上面的意思,这里给出一个示例。在32位系统中,假如一个int变量在内存中的地址是0x00ff42c3,因为int是占用4个字节,所以它的尾地址应该是0x00ff42c6,这个时候CPU为了读取这个int变量的值,就需要先后读取两个word大小的块,分别是0x00ff42c0~0x00ff42c30x00ff42c4~0x00ff42c7,然后通过移位等一系列的操作来得到,在这个计算的过程中还有可能引起一些总线数据错误的。但是如果编译器对变量地址进行了对齐,比如放在0x00ff42c0,CPU就只需要一次就可以读取到,这样的话就加快读取效率。

          在这里给出三个个人认为讲解比较好的网址,供大家参考,英语比较好的朋友,推荐阅读。

            a、Data structure alignmenthttp://en.wikipedia.org/wiki/Data_structure_alignment

            b、Data alignment: Straighten up and fly righthttp://www.ibm.com/developerworks/library/pa-dalign/

            c、About Data Alignmenthttp://msdn.microsoft.com/zh-cn/library/ms253949.aspx

          1、基本数据对齐

                 在X86,32位系统下基于Microsoft、Borland和GNU的编译器,有如下数据对齐规则:

                 a、一个char(占用1-byte)变量以1-byte对齐。

                 b、一个short(占用2-byte)变量以2-byte对齐。

                 c、一个int(占用4-byte)变量以4-byte对齐。

                 d、一个long(占用4-byte)变量以4-byte对齐。

                 e、一个float(占用4-byte)变量以4-byte对齐。

                 f、一个double(占用8-byte)变量以8-byte对齐(注:在Linux平台下是4-byte对齐,超过4-byte都是以4-byte对齐)。

                 g、一个long double(占用12-byte)变量以4-byte对齐。

                 h、任何pointer(占用4-byte)变量以4-byte对齐。

                而在64位系统下,与上面规则对比有如下不同:

                 a、一个long(占用8-byte)变量以8-byte对齐。

                 b、一个double(占用8-byte)变量以8-byte对齐。

                 c、一个long double(占用16-byte)变量以16-byte对齐。

                 d、任何pointer(占用8-byte)变量以8-byte对齐。

          2、结构体数据对齐

          结构体数据对齐,是指结构体内的各个数据对齐。在结构体中的第一个成员的首地址等于整个结构体的变量的首地址,而后的成员的地址随着它声明的顺序和实际占用的字节数递增。为了总的结构体大小对齐,会在结构体中插入一些没有实际意思的字符来填充(padding)结构体。

   1:  #include <iostream>
   2:   
   3:  using namespace std;
   4:   
   5:  union
   6:  {
   7:      struct
   8:      {
   9:          char i:1;
  10:          char j:2;
  11:          char m:3;
  12:      }s;
  13:   
  14:      char ch;
  15:  }r;
  16:   
  17:  struct
  18:  {
  19:      char i;
  20:      double j;
  21:      int m;
  22:  }node;
  23:   
  24:  int _tmain(int argc, _TCHAR* argv[])
  25:  {
  26:      r.s.i = 1;
  27:      r.s.j = 2;
  28:      r.s.m = 3;
  29:   
  30:      node.i = 'm';
  31:      node.j = 3.1415926;
  32:      node.m = 100;
  33:   
  34:      cout<<" r.ch = "<<(int)r.ch<<" = 0x"<<hex<<(int)r.ch<<endl
  35:          <<" sizeof(r) = "<<sizeof(r)<<endl;
  36:      
  37:      cout.unsetf(ios::hex);
  38:   
  39:      cout<<" sizeof(node) = "<<sizeof(node)<<endl;
  40:   
  41:      system("PAUSE");
  42:   
  43:      return 0;
  44:  }
  45:   

              运行结果截图如下:

         通过上面的运行截图,可以得知,sizeof(r) = 1,sizeof(node)=24;首先看r存储在首地址0x0111a150,node的首地址 为0x0111a138,这个符合先定义先分配空间,并且是从内存地址大到小的顺序来分配空间。它们之间相差(0x0111a150-0x0111a138)=0x18=24byte(注意这里是16进制计算,借116,不是习惯性的当10)。而且通过每个成员的地址也知道,m和j之间隔8字节,double是占用8字节,j和i之间也是8字节,但是char只占用了一个字节,其余相差的7个字节使用0来填充。同样int成员在后面的4个高字节中也填充了0,以满足8字节对齐(前面4个字节按小端高字节高地址低字节低地址存放)。同样r只占用0x0111a150这个字节,值为0x1d=29。

        在结构体中,成员数据对齐满足以下规则:

        a、结构体中的第一个成员的首地址也即是结构体变量的首地址。

        b、结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。

        c、结构体的总大小是对齐模数(对齐模数等于#pragma pack(n)所指定的n与结构体中最大数据类型的成员大小的最小值)的整数倍。

        在看另外一个示例,来理解以上规则。

   1:  #include "stdafx.h"
   2:   
   3:  #include <iostream>
   4:   
   5:  using namespace std;
   6:   
   7:  struct
   8:  {
   9:      char a;
  10:      int b;
  11:      short c;
  12:      char d;
  13:  }dataAlign;
  14:   
  15:  struct
  16:  {
  17:      char a;
  18:      char d;
  19:      short c;
  20:      int b;
  21:      
  22:  }dataAlign2;
  23:   
  24:  int _tmain(int argc, _TCHAR* argv[])
  25:  {
  26:      dataAlign.a = 'A';
  27:      dataAlign.b = 0x12345678;
  28:      dataAlign.c = 0xABCD;
  29:      dataAlign.d = 'B';
  30:   
  31:      dataAlign2.a = 'A';
  32:      dataAlign2.b = 0x12345678;
  33:      dataAlign2.c = 0xABCD;
  34:      dataAlign2.d = 'B';
  35:   
  36:      cout<<" sizeof(dataAlign)  = "<<sizeof(dataAlign)<<endl;
  37:      cout<<" sizeof(dataAlign2) = "<<sizeof(dataAlign2)<<endl;
  38:   
  39:      system("PAUSE");
  40:   
  41:      return 0;
  42:  }

   运行结果截图如下:

         仔细观察,会发现虽然是一样的数据类型的成员,只不过声明的顺序不同,结构体占用的大小也不同,一个8-byte一个12-byte。为什么这样,下面进行具体分析。

         首先来看dataAlign2,第一个成员的地址等于结构体变量的首地址,第二个成员char类型,为了满足规则b,它相对于结构体的首地址的偏移量必须是char=1的倍数,由于前面也是char,故不需要在第一个和第一个成员之间填充,直接满足条件。第三个成员short=2如果要满足规则b,也不需要填充,因为它的偏移量已经是2。同样第四个也因为偏移量int=4,不需要填充,这样结构体总共大小为8-byte。最后来验证规则c,在VC中默认的#pragma pack(n)中的n=8,而结构体中数据类型大小最大的为第四个成员int=4,故对齐模数为4,并且8 mode 4 = 0,所以满足规则c。这样整个结构体的总大小为8。结合上面运行结果截图的红色框,可以验证。

         对于dataAlign,第一个成员等于结构体变量首地址,偏移量为0,第二个成员为int=4,为了满足规则b,需要在第一个成员之后填充3-byte,让它相对于结构体首地址偏移量为4,结合运行结果截图,可知&dataAlign.a = 0x01109140,而&dataAlign.b = 0x01109144,它们之间相隔4-byte,0x01109141~0x01109143三个字节被0填充。第三个成员short=2,无需填充满足规则b。第四个成员char=1,也不需要填充。OK,结构体总大小相加4 + 4 + 2 + 1 = 11。同样最后需要验证规则c,结构体中数据类型大小最大为第二个成员int=4,比VC默认对齐模数8小,故这个结构体的对齐模数仍然为4,显然11 mode 4 != 0,故为了满足规则c,需要在char后面填充一个字节,这样结构体变量dataAlign的总大小为4 + 4 + 2 + 2 = 12。

         好了,再来看看位段(也叫位域)这种数据类型在内存中的对齐。一个位域必须存储在同一个字节中,不能跨字节,比如跨两个字节。如果一个字节所剩空间不够存储另一位位域时,应该从下一个字节存放该位域。在满足成员数据对齐的规则下,还满足如下规则:

         d、如果相邻位域类型相同,并且它俩位域宽度之和小于它的数据类型大小,则后面的字段紧邻前面的字段存储。

         e、如果相邻位域类型相同,但是它俩位域宽度之和大于它的数据类型大小,则后面的字段将从新的存储单元开始,其偏移量为其类型的整数倍。

         f、如果相邻位域类型不同,在VC中是不采取压缩方式,但是GCC会采取压缩方式。

         具体的结合下面示例来理解,具体代码为:              

   1:  #include <iostream>
   2:   
   3:  using namespace std;
   4:   
   5:  struct
   6:  {
   7:      char a:4;
   8:      int b:6;
   9:  }bitChar2;
  10:   
  11:  struct
  12:  {
  13:      char a:3;
  14:      char b:3;
  15:      char c:7;
  16:      double d;
  17:      int e:4;
  18:      int f:30;
  19:  }bitChar;
  20:   
  21:  int _tmain(int argc, _TCHAR* argv[])
  22:  {
  23:      bitChar2.a = 7;
  24:      bitChar2.b = 32;
  25:      cout<<" sizeof(bitChar2) = "<<sizeof(bitChar2)<<endl;
  26:   
  27:      bitChar.a = 6;
  28:      bitChar.b = 4;
  29:      bitChar.c = 45;
  30:      bitChar.d = 100.0;
  31:      bitChar.e = 7;
  32:      bitChar.f = 0x12345678;
  33:      cout<<"sizeof(bitChar) = "<<sizeof(bitChar)<<endl;
  34:   
  35:      system("PAUSE");
  36:      return 0;
  37:  }

                运行结果截图如下:

            首先来分析bitChar2,因为满足规则f,在VC下不压缩,同时要满足规则a、b、c。所以第二个成员需要最低偏移量为4,第一个成员后需要填充3-byte。再看第二个bitChar,首先成员a、b满足规则d,故需要填充在0x00ab9138这个字节内,具体存储顺序见下图:

b:3

a:3

7

6

5

4

3

2

1

0

0

0

1

0

0

1

1

0

2

6

          而第二个成员和第三个成员满足规则e,位域之和大于sizeof(char)=1的大小,所以需要一个偏移量。而第四个成员double=8为了满足规则b,必须在第三个成员之后填充6-byte,满足最小偏移量8。第五个成员不需要偏移,故无需填充。而第六个成员和第五个成员满足规则e,所以需要从新的存储单元开始存储,偏移量为int=4的整数倍,然后存储最后的成员e,中间需要填充3-byte。

         由此可以得出总的大小为1 + 1 + 6 + 8 + 4 + 4 = 24,满足规则c,即是24 mode 8 = 0

四,关于#pragma pack(n)

         #pragma pack(push) //保存对齐状态
         #pragma pack(n) /设置对齐模数(选择n和一般情况下选出来的模数的较小者做对齐模数)
         #pragma pack(pop) //恢复对齐状态

Explicitly Release Resources In C#

2012-05-23 15:28 by libiver, 阅读(857) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2012/05/23/2514862.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog According the last blo... 阅读全文

C# Constructor and Destructor

2012-05-22 18:43 by libiver, 阅读(2001) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2012/05/22/2513719.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog 根据今天的C#复习,对构造函数和析构函数进行了一下梳理。它们具体在结构体... 阅读全文

C# Data Types

2012-05-21 19:08 by libiver, 阅读(559) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接: http://www.cnblogs.com/leezhm/archive/2012/05/21/2512079.html 开拓进取的小乌龟———->cnBlogs 点滴点点滴滴 Blog In C-Sharp, there are two general ... 阅读全文

Windows Presentation Foundation系列(5)---自定义布局面板

2011-07-06 12:41 by libiver, 阅读(1641) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2011/07/06/2099083.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog 在这篇文章里面记录下,学习Essential Windows Presentation Foundation一书中自定义布局面板的实例和我的理解。 在实际的项目中,可能遇到WPF已经提供的布局面板并不能满足我们要求的情况,比如我们需要把控件自动排列成一个圆圈,这个时候就可能需要自己来构建自定义布局满足 阅读全文

Windows Presentation Foundation系列(4)----公共布局属性

2011-07-01 16:55 by libiver, 阅读(591) 阅读, 推荐(3) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2011/07/01/2095649.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog 在WPF的布局中,除了不同的面板使用的不同的附加属性外,还有一些公共的布局属性。它们的存在,让布局系统更加功能强大,控制更精确。它们分别是 属性 说明 Width 为Element指定一个宽度。 Height 为Element指定一个高度。 MinWidth 允许的元素最小宽度。 MinHeight 允许的 阅读全文

Window Presentation Foundation系列(3)---布局系统简介

2011-06-29 01:38 by libiver, 阅读(729) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2011/06/29/2092847.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog 布局系统是WPF中非常重要的一部分知识,也是WPF的精华,很多时候决定了软件的成败。好的布局牵涉到程序的性能,复杂度,耦合度等等。好的布局为广大的程序员提供了充分的控制。 为了布局的方便,WPF为我们提供了如下几种布局面板。 面板名称 说明 Canvas 定义一个区域,在此区域内,您可以使用相对于 阅读全文

Window Presentation Foundation系列(2)---探索Application类

2011-06-21 18:58 by libiver, 阅读(561) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2011/06/21/2086308.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 Blog 一个WPF应用程序必须有一个Application对象实例或者它的子类实例,它代表了WPF的一个windows进程,它提供了WPF程序的生命周期,并且集成了ClickOnce部署功能。或者更明确地说,在WPF中应用程序就是System.Windows命名空间下Application类或者它的子类的一 阅读全文

Window Presentation Foundation系列 (1)---从HelloWorld认知WPF

2011-06-21 17:22 by libiver, 阅读(511) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://www.cnblogs.com/leezhm/archive/2011/06/21/2086239.html 开拓进取的小乌龟------->cnBlogs 点滴点点滴滴 的Blog Ok,作为一个Programmer,绝大部分人对一种全新的语言的第一个程序应该都是Hello,World吧。在这里我也从这个开始,一个最简单的Hello World。代码如下: 1: using System; 2: using System.Windows; 3: 4: namespace HelloW 阅读全文

Window Presentation Foundation系列---探索Application类

2010-11-04 17:49 by libiver, 阅读(345) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/11/04/5987896.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog 一个WPF应用程序必须有一个Application对象实例或者它的子类实例,它代表了WPF的一个windows进程,它提供了WPF程序的生命周期,并且集成了ClickOnce部署功能。或者更明确地说,在WPF中应用程序就是System.Windows命名空间下Application类或者它的子类的一个实例。 Applicat 阅读全文

Window Presentation Foundation系列---从HelloWorld认知WPF

2010-11-02 17:37 by libiver, 阅读(221) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/11/02/5982660.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog ok,作为一个Programmer,绝大部分人对一种全新的语言的第一个程序应该都是Hello,World吧。在这里我也从这个开始,一个最简单的Hello World。代码如下:using System;using System.Windows;namespace HelloWorld{ class HelloWorld { 阅读全文

相机标定原理———标定原理介绍

2010-10-30 16:23 by libiver, 阅读(675) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/10/30/5976261.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog由于在word中包含大量的公式和矩阵的表示图片,csdn博客不支持直接粘贴,为了方便我就直接整篇文章截图了. 阅读全文

相机标定原理———数学基础

2010-10-30 15:38 by libiver, 阅读(2116) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/10/30/5976178.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog由于在word中包含大量的公式和矩阵的表示图片,csdn博客不支持直接粘贴,为了方便我就直接整篇文章截图了. 阅读全文

第四期FLASH专家交流会 7月24日 广州东方国际饭店

2010-07-06 16:36 by libiver, 阅读(199) 阅读, 推荐(0) 推荐, 收藏,
摘要:谈熠<tanyi@smartgf.com> 第四期FLASH专家交流会 7月24日 广州东方国际饭店 免费参加,火热报名中! swfsh.com<tanyi@swfsh.com> Fri, Jul 2, 2010 at 5:23 PM To:tanyi@smartgf.com 第四期FLASH专家交流会 7月24日 广州东方国际饭店活动主题: 新技术和开发经验免费参加,座位有限,报名请点击 SWFSH.COM中国FLASH开发者交流会是一个双月定期举行的开发者交流会,在上海已经成功的举办了三届了,共有近600名FLASH专业开发者参加。7月24日,第四届FLASH开发. 阅读全文

IP数据包包头分析

2010-06-02 17:13 by libiver, 阅读(1185) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/06/02/5642818.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog首先根据IP协议定义IP数据包头(关于IP协议头各部分的定义,具体参考http://en.wikipedia.org/wiki/IPv4),注意严格的类型大小,不然数据转换会出现错误。/* // http://en.wikipedia.org/wiki/IPv4-|------------->16<-------- 阅读全文

基于OpenGL的三种直线生成算法

2010-05-25 15:33 by libiver, 阅读(908) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/05/25/5622943.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog(一)数值微分(DDA)法 设过端点P0(x0 y0)、P1(x1 y1)的直线段为L(P0 P1),则直线段L的斜率 L的起点P0的横坐标x0向L的终点P1的横坐标x1步进,取步长=1(个象素),用L的直线方程y=kx+b计算相应的y坐标,并取象素点(x round(y))作为当前点的坐标。因为: yi+1 = kxi+1+ 阅读全文

摄像机标定和图像径向畸变校正

2010-03-16 12:25 by libiver, 阅读(830) 阅读, 推荐(1) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。本文链接:http://blog.csdn.net/li_007/archive/2010/03/16/5384937.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog这段时间断断续续在弄这个摄像头的标定和图像畸形矫正的问题,基本差不多了,乘休息时间,发点成果和大家分享吧!一、标定关于摄像头的标定,说实话网上的资料太多了,方法也很多的。个人觉得想要研究这个的话,可以先了解基本原理,然后看opencv的例子calibration。如果你还了解的更深入的话,建议下载一些论文看看。当然我推荐一个网 阅读全文

在Directshow中使用VMR9

2010-03-02 14:56 by libiver, 阅读(724) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://blog.csdn.net/li_007/archive/2010/03/02/5338976.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog废话就少说了,把这段时间做的某***活动要用播发器的部分Directshow代码发出来,方便大家使用(声明:遵循LGPL协议)。本来同事想用openframeworks使用quicktime来播放这个3084*720的高清AD片子的,可是播放的时候有点卡,所以没办法就只有再次自己用directshow来写,现在分享的代码可以 阅读全文

Touchlib源码注释-----TUIOObject.as TUIOEvent.as TUIOCursor.as

2010-01-05 11:31 by libiver, 阅读(290) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://blog.csdn.net/li_007/archive/2010/01/05/5134270.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴Blog还是继续把剩余的整理贴出来。欢迎大家指正。TUIO.as文件详细注释TUIOObject.as文件详细注释TUIOEvent.as文件详细注释TUIOCursor.as文件详细注释TUIOObject.as文件package com.touchlib { import flash.display.Sprite; import 阅读全文

Touchlib源码注释-----TUIO.as

2010-01-01 18:32 by libiver, 阅读(425) 阅读, 推荐(0) 推荐, 收藏,
摘要:声明:欢迎任何人和组织转载本blog中文章,但必须标记文章原始链接和作者信息。 本文链接:http://blog.csdn.net/li_007/archive/2010/01/01/5118098.aspx开拓进取的小乌龟------->CSDN点滴点点滴滴BlogTUIO.as文件详细注释TUIOObject.as TUIOEvent.as TUIOCursor.as文件详细注释 研究了一段时间的multiTouch,根据自己的理解也对代码做了很多注释,今天整理了一下Touchlib这个库的Actionscript 3版本的源码注释,现在发布出来,希望和大家一起讨论修正。也欢迎大家指 阅读全文
点击右上角即可分享
微信分享提示