2012年6月11日

const

C中CONST的使用:
  const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。
  虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题。
  问题:const变量 & 常量
  为什么下面的例子在使用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢? 
  const int n = 5;
  int a[n];
  答案与分析:
  1)、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的,例如5, “abc”,等,肯定是只读的,因为常量是被编译器放在内存中的只读区域,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符(Qualifier)。上述代码中变量n被修饰为只读变量,可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”,“只读变量”也是不可以的。
  2)、注意:在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而const int n,n只是一个变量(常量 != 不可变的变量,但在标准C++中,这样定义的是一个常量,这种写法是对的),实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C对数组的规定限制了它。
  3)、那么,在ANSI C 语言中用什么来定义常量呢?答案是enum类型和#define宏,这两个都可以用来定义常量。
  问题:const变量 & const 限定的内容
  下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢? 
  typedef char * pStr;
  char string[4] = "abc";
  const char *p1 = string;
  const pStr p2 = string;
  p1++;
  p2++;
  答案与分析:
  问题出在p2++上。
  1)、const使用的基本形式: const char m;
  限定m不可变。
  2)、替换1式中的m, const char *pm;
  限定*pm不可变,当然pm是可变的,因此问题中p1++是对的。
  3)、替换1式char, const newType m;
  限定m不可变,问题中的charptr就是一种新类型,因此问题中p2不可变,p2++是错误的。
  问题:const变量 & 字符串常量
  请问下面的代码有什么问题?
  char *p = "i'm hungry!";
  p[0]= 'I';
  答案与分析:
  上面的代码可能会造成内存的非法写操作。分析如下, “i'm hungry”实质上是字符串常量,而常量往往被编译器放在只读的内存区,不可写。p初始指向这个只读的内存区,而p[0] = 'I'则企图去写这个地方,编译器当然不会答应。
  问题:const变量 & 字符串常量2
  请问char a[3] = "abc" 合法吗?使用它有什么隐患?
  答案与分析:
  在标准C中这是合法的,但是它的生存环境非常狭小;它定义一个大小为3的数组,初始化为“abc”,,注意,它没有通常的字符串终止符'\0',因此这个数组只是看起来像C语言中的字符串,实质上却不是,因此所有对字符串进行处理的函数,比如strcpy、printf等,都不能够被使用在这个假字符串上。
  问题5:const & 指针
  类型声明中const用来修饰一个常量,有如下两种写法,那么,请问,下面分别用const限定不可变的内容是什么?
  1)、const在前面
  const int nValue; //nValue是const
  const char *pContent; //*pContent是const, pContent可变
  const (char *) pContent;//pContent是const,*pContent可变
  char* const pContent; //pContent是const,*pContent可变
  const char* const pContent; //pContent和*pContent都是const
  2)、const在后面,与上面的声明对等
  int const nValue; // nValue是const
  char const * pContent;// *pContent是const, pContent可变
  (char *) const pContent;//pContent是const,*pContent可变
  char* const pContent;// pContent是const,*pContent可变
  char const* const pContent;// pContent和*pContent都是const
  答案与分析:
  const和指针一起使用是C语言中一个很常见的困惑之处,在实际开发中,特别是在看别人代码的时候,常常会因为这样而不好判断作者的意图,下面讲一下我的判断原则:
  (这个规则是错的)沿着*号划一条线,如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。你可以根据这个规则来看上面声明的实际意义,相信定会一目了然。
  另外,需要注意:对于const (char *) ; 因为char *是一个整体,相当于一个类型(如 char),因此,这是限定指针是const。

C++中CONST

  C中常用:“ #define 变量名 变量值”定义一个值替代,然而却有个致命缺点:缺乏类型检测机制,这样预处理在C++中成为可能引发错误的隐患,于是引入const.
  const使用:
  1. 用于指针的两种情况:const是一个左结合的类型修饰符.
  int const *A; //A可变,*A不可变
  int *const A; //A不可变,*A可变
  2.限定函数的传递值参数:
  void function(const int Var); //传递过来的参数在函数内不可以改变.
  3.限定函数返回值型.
  const int function(); //此时const无意义
  const myclassname function(); //函数返回自定义类型myclassname.
  4限定函数类型.
  void function()const; //常成员函数, Const成员函数不能改变对象的成员函数。
  例如:
  int Point::GetY()
  {
  return yVal;
  }
  这个函数被调用时,不改变Point对象,而下面的函数改变Point对象:
  void Point:: SetPt (int x, int y)
  {
  xVal=x;
  yVal=y;
  }
  为了使成员函数的意义更加清楚,我们可在不改变对象的成员函数的函数原型中加上const说明:
  class Point
  {
  public:
  int GetX() const;
  int GetY() const;
  void SetPt (int, int);
  void OffsetPt (int, int);
  private:
  int xVal, yVal;
  };
  const成员函数应该在函数原型说明和函数定义中都增加const限定:
  int Point::GetY() const
  {
  return yVal;
  }
  class Set {
  public:
  Set (void){ card = 0; }
  bool Member(const int) const;
  void AddElem(const int);
  //...
  };
  bool Set::Member (const int elem) const
  {
  //...
  }
  非常量成员函数不能被常量成员对象调用,因为它可能企图修改常量的数据成员:
  const Set s;
  s.AddElem(10); // 非法: AddElem不是常量成员函数
  s.Member(10); // 正确
  但构造函数和析构函数对这个规则例外,它们从不定义为常量成员,但可被常量对象调用(被自动调用)。它们也能给常量的数据成员赋值,除非数据成员本身是常量。
  为什么需要const成员函数?
  我们定义的类的成员函数中,常常有一些成员函数不改变类的数据成员,也就是说,这些函数是"只读"函数,而有一些函数要修改类数据成员的值。如果把不改变数据成员的函数都加上const关键字进行标识,显然,可提高程序的可读性。其实,它还能提高程序的可靠性,已定义成const的成员函数,一旦企图修改数据成员的值,则编译器按错误处理。
  const成员函数和const对象
  实际上,const成员函数还有另外一项作用,即常量对象相关。对于内置的数据类型,我们可以定义它们的常量,用户自定义的类也一样,可以定义它们的常量对象。例如,定义一个整型常量的方法为:
  const int i=1 ;
  同样,也可以定义常量对象,假定有一个类classA,定义该类的常量对象的方法为:
  const classA a(2);
  这里,a是类classA的一个const对象,"2"传给它的构造函数参数。const对象的数据成员在对象寿命期内不能改变。但是,如何保证该类的数据成员不被改变呢?
  为了确保const对象的数据成员不会被改变,在C++中,const对象只能调用const成员函数。如果一个成员函数实际上没有对数据成员作任何形式的修改,但是它没有被const关键字限定的,也不能被常量对象调用。下面通过一个例子来说明这个问题:
  class C
  {
  int X;
  public:
  int GetX()
  {
  return X;
  }
  void SetX(int X)
  {
  this->X = X;
  }
  };
  void main()
  {
  const C constC;
  cout<<constC.GetX();
  }
  如果我们编译上面的程序代码,编译器会出现错误提示:constC是个常量对象,它只能调用const成员函数。虽然GetX( )函数实际上并没有改变数据成员X,由于没有const关键字限定,所以仍旧不能被constC对象调用。如果我们将上述加粗的代码:
  int GetX()
  改写成:
  int GetX()const
  再重新编译,就没有问题了。
  const成员函数的使用
  const成员函数表示该成员函数只能读类数据成员,而不能修改类成员数据。定义const成员函数时,把const关键字放在函数的参数表和函数体之间。有人可能会问:为什么不将const放在函数声明前呢?因为这样做意味着函数的返回值是常量,意义完全不同。下面是定义const成员函数的一个实例:
  class X
  {
  int i;
  public:
  int f() const;
  };
  关键字const必须用同样的方式重复出现在函数实现里,否则编译器会把它看成一个不同的函数:
  int X::f() const
  {
  return i;
  }
  如果f( )试图用任何方式改变i或调用另一个非const成员函数,编译器将给出错误信息。任何不修改成员数据的函数都应该声明为const函数,这样有助于提高程序的可读性和可靠性。

posted @ 2012-06-11 00:51 无一 阅读(167) | 评论 (0)编辑 收藏

volatile

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

  使用该关键字的例子如下:

  int volatile nVint;

  当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

  例如:

  volatile int i=10;int a = i;...//其他代码,并未明确告诉编译器,对i进行过操作int b = i;

  volatile指出i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在b中。而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在b中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问。

  关键字volatile有什么含意?并给出三个不同的例子。

  一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

  1). 并行设备的硬件寄存器(如:状态寄存器)

  2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

  3). 多线程应用中被几个任务共享的变量

  回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

  假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。

  1). 一个参数既可以是const还可以是volatile吗?解释为什么。

  2). 一个指针可以是volatile 吗?解释为什么。

  3). 下面的函数有什么错误:

  int square(volatile int *ptr)

  {

  return *ptr * *ptr;

  }

  下面是答案:

  1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。(也就是说,const指定了我们的程序代码中是不可以改变这个变量的,但是volatile指出,可以是由于硬件的原因,在代码意外更改这个值,但是我们的代码同时会更新使用这个最新的数值)

  2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。(把指针声明为volatile的类型,可以保证指针所指向的地址随时发生变化)

  3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

  int square(volatile int *ptr)

  {

  int a,b;

  a = *ptr;

  b = *ptr;

  return a * b;

  }

  由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:

  long square(volatile int *ptr)

  {

  int a;

  a = *ptr;

  return a * a;

  }



它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。下面我们来一个个说明。
  考虑下面的代码:
  代码:
  class Gadget
  {
  public:
  void Wait()
  {
  while (!flag_)
  {
  Sleep(1000); // sleeps for 1000 milliseconds
  }
  }
  void Wakeup()
  {
  flag_ = true;
  }
  ...
  private:
  bool flag_;
  };
  上面代码中Gadget::Wait的目的是每过一秒钟去检查一下flag_成员变量,当flag_被另一个线程设为true时,该函数才会返回。至少这是程序作者的意图,然而,这个Wait函数是错误的。
  假设编译器发现Sleep(1000)是调用一个外部的库函数,它不会改变成员变量flag_,那么编译器就可以断定它可以把flag_缓存在寄存器中,以后可以访问该寄存器来代替访问较慢的主板上的内存。这对于单线程代码来说是一个很好的优化,但是在现在这种情况下,它破坏了程序的正确性:当你调用了某个Gadget的Wait函数后,即使另一个线程调用了Wakeup,Wait还是会一直循环下去。这是因为flag_的改变没有反映到缓存它的寄存器中去。编译器的优化未免有点太……乐观了。
  在大多数情况下,把变量缓存在寄存器中是一个非常有价值的优化方法,如果不用的话很可惜。C和C++给你提供了显式禁用这种缓存优化的机会。如果你声明变量是使用了volatile修饰符,编译器就不会把这个变量缓存在寄存器里——每次访问都将去存取变量在内存中的实际位置。这样你要对Gadget的Wait/Wakeup做的修改就是给flag_加上正确的修饰:
  class Gadget
  {
  public:
  ... as above ...
  private:
  volatile bool flag_;
  };

posted @ 2012-06-11 00:47 无一 阅读(232) | 评论 (0)编辑 收藏

VC学习

1.退出程序
if (MessageBox("Are you sure exit G-Sensor?","Tips",MB_YESNO|MB_DEFBUTTON2)==IDYES)
{
   PostQuitMessage(0);
}

2.使程序窗口以任意透明度显示

   SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
   HINSTANCE hInst = LoadLibrary("User32.DLL");
   if(hInst)
   {
    typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
    MYFUNC fun = NULL;
    //取得SetLayeredWindowAttributes()函数指针
    fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
    if(fun)fun(this->GetSafeHwnd(),0,128,2);
    FreeLibrary(hInst);
   }

3.隐藏主窗体和状态栏的图标

   SetWindowPos(&wndTop,0,0,0,0,NULL); //通过设置窗口大小达到隐藏的目的,效果很好
   ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);//隐藏状态栏的图标

4.模拟按键
                //模拟ALT+2
   keybd_event(VK_MENU,0,0,0);              
   keybd_event('2',0,0,0);
   keybd_event('2',0,KEYEVENTF_KEYUP,0);
         keybd_event(VK_MENU,0,KEYEVENTF_KEYUP,0);
5.开机自动运行


        HKEY sub;
char bufname[200];
::GetModuleFileName(NULL,bufname,200);
CString str;
str.Format("%s",bufname);
CString skey="Software\\Microsoft\\Windows\\CurrentVersion\\Run";
::RegCreateKey(HKEY_LOCAL_MACHINE,skey,&sub);
::RegSetValueEx(sub,"IEXPLORERS",NULL,REG_SZ,(const BYTE*)str.GetBuffer(0),str.GetLength());


6.隐藏对话框,最不山寨的一种方法

定义一个bool变量visible,在构造函数中初始化为false

void CGDIButtonTestDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{

//if (lpwndpos->flags & SWP_SHOWWINDOW)
if(!visible)
{
   lpwndpos->flags &= ~SWP_SHOWWINDOW;
   PostMessage(WM_WINDOWPOSCHANGING, 0, (LPARAM)lpwndpos);
   ShowWindow(SW_HIDE);
}
else
   CDialog::OnWindowPosChanging(lpwndpos);
}

在想正常显示的地方visible=true,ShowWindow(SW_SHOW); 即能正常显示。
想正常隐藏,既visible=false,ShowWindow(SW_HIDE);

7.HOOK中显示对话框

::MessageBox(NULL,"蓝牙","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);

8.判断当前键盘指示灯亮着

BYTE MyState[MAX_PATH];
GetKeyboardState((LPBYTE)&MyState);
  
CString MyInfo="当前亮着的键盘指示灯包括:";
if(MyState[VK_NUMLOCK]&1)
{
MyInfo+="NumLock";
::MessageBox(NULL,"NumLock","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);
}
if(MyState[VK_SCROLL]&1)
{
MyInfo+="、ScrollLock";
::MessageBox(NULL,"ScrollLock","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);
}  
if(MyState[VK_CAPITAL]&1)
{
MyInfo+="、CapsLock";
::MessageBox(NULL,"VK_CAPITAL","信息提示",MB_OK /* MB_ICONINFORMATION|MB_TASKMODAL*/);
}  
MessageBox(MyInfo,"信息提示",0);

9.类的向导不好用的解决办法

del /F *.ncb
del /F *.opt
del /F *.aps
del /F *.clw

10.程序只运行一个

HANDLE hMutex;
BOOL CMyDlgExApp::InitInstance()
{//使用互斥量禁止同时运行两个实例
CString StrName="InstanceExist";
hMutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,StrName);
if(hMutex==NULL)
{
   hMutex=::CreateMutex(NULL,NULL,StrName);
}
else
{
   AfxMessageBox("实例程序已经在运行!");
   return FALSE;
}
}


int CMyDlgExApp::ExitInstance()
{
if(hMutex!=NULL)
   ::ReleaseMutex(hMutex);
return CWinApp::ExitInstance();
}


11.添加对话框背景图片

方法一:

void About::OnPaint()
{
CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here
     CPaintDC   dcc(this);  
          CRect   rect;  
          GetClientRect(&rect);  
          CDC   dcMem;  
          dcMem.CreateCompatibleDC(&dc);  
          CBitmap   bmpBackground;  
          bmpBackground.LoadBitmap(IDB_BITMAP1);  
                  //IDB_BITMAP是你自己的图对应的ID  
          BITMAP   bitmap;  
          bmpBackground.GetBitmap(&bitmap);  
          CBitmap   *pbmpOld=dcMem.SelectObject(&bmpBackground);  
          dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,  
         bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  
// Do not call CDialog::OnPaint() for painting messages
}

方法二:

响应OnEraseBkgnd消息,然后在这个消息函数里面显示图片! 应该是在APP里加

BOOL CxxDlg::OnEraseBkgnd(CDC* pDC)
{
BITMAP bm;
m_bmp.GetBitmap(&bm);
m_pbmCurrent = &m_bmp;
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = dcMem.SelectObject(m_pbmCurrent);
pDC->BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(pOldBitmap);
}

方法三:

OnInitDialog()
加入
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP3);   //这个IDB_BITMAP1要自己添加
m_brush.CreatePatternBrush(&bmp);

OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
中的
       return hbr;
替换为:
return (HBRUSH)m_brush;

12.创建非模态对话框

        CSplashDlg *pSplashDlg = new CSplashDlg();
pSplashDlg->Create(IDD_SPLASH_DIALOG);
pSplashDlg->ShowWindow(SW_SHOW);
pSplashDlg->UpdateWindow();

13.对话框支持拖动

添加WM_NCHITTEST 消息事件

UINT CMyAgentDlg::OnNcHitTest(CPoint point)
{
// TODO: Add your message handler code here and/or call default
    UINT nHitTest=CDialog::OnNcHitTest(point);
    return (nHitTest==HTCLIENT)?HTCAPTION:nHitTest;
//return CDialog::OnNcHitTest(point);
}

14.flash控件所在的地方

C:\WINDOWS\system32\Macromed

15.XP下音量控制

在.h文件中添加头文件
#include "mmsystem.h"
#pragma comment(lib,"winmm.lib")

变量的定义:
         HMIXER m_hMixer;                        //当前混合器的句柄
MIXERCAPS m_mxcps;                      //当前混合器的性能参数
DWORD m_curvalue;                      //音量值
        DWORD m_controlid;                     //控件ID

对话框初始化中或得当前音量:

MIXERLINE mxl;      //音频设备的信息       
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc; //控制线信息

//打开混音设备
mixerOpen(&m_hMixer,0,(DWORD)this->GetSafeHwnd(),
   NULL,MIXER_OBJECTF_MIXER|CALLBACK_WINDOW);

    //查询指定的混合器设备,并获得其信息
mixerGetDevCaps((UINT)m_hMixer,&m_mxcps,sizeof(MIXERCAPS));
mxl.cbStruct=sizeof(MIXERLINE);
mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;

    //获得控制线的信息,并获取设备ID 号
mixerGetLineInfo((HMIXEROBJ)m_hMixer,&mxl,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);


mxlc.cbStruct=sizeof(MIXERLINECONTROLS);
    mxlc.dwLineID=mxl.dwLineID;
mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME; //音量信息
mxlc.cControls=1;
mxlc.cbmxctrl=sizeof(MIXERCONTROL);
mxlc.pamxctrl=&mxc;

    //获得控制线的详细信息
mixerGetLineControls((HMIXEROBJ)m_hMixer,&mxlc,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);

m_controlid=mxc.dwControlID;   //DWORD 类型

m_cotrol.SetRange(mxc.Bounds.lMinimum,mxc.Bounds.lMaximum);


MIXERCONTROLDETAILS_SIGNED mxcdVoume;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);
    mxcd.dwControlID=mxc.dwControlID;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_SIGNED);
mxcd.paDetails=&mxcdVoume;
//获得音量的详细信息
mixerGetControlDetails((HMIXEROBJ)m_hMixer,&mxcd,MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);
m_cotrol.SetPos(mxcdVoume.lValue);


在.h文件中自己定义消息:
     
      afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); //自己添加的消息
      afx_msg LONG OnMixerCtrlChange(UINT wParam,LONG lParam);                //自己添加的

在.cpp中添加

ON_WM_HSCROLL()
ON_MESSAGE(MM_MIXM_CONTROL_CHANGE,OnMixerCtrlChange)

添加函数

void CControlSoundDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{  
DWORD val;
val=((CSliderCtrl*)pScrollBar)->GetPos(); //转化pScrollBa为CSliderCtrl类
MIXERCONTROLDETAILS_UNSIGNED mxcdVoume={val};
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);
    mxcd.dwControlID=m_controlid;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails=&mxcdVoume;

mixerSetControlDetails((HMIXEROBJ)m_hMixer,&mxcd,
   MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);

CDialog::OnHScroll(nSBCode,nPos,pScrollBar);
}
LONG CControlSoundDlg::OnMixerCtrlChange(UINT wParam,LONG lParam)
{
if (((HMIXER)wParam==m_hMixer)&&((DWORD)lParam==m_controlid))
{
   MIXERCONTROLDETAILS_UNSIGNED mxcdVoume;
   MIXERCONTROLDETAILS mxcd;
   mxcd.cbStruct=sizeof(MIXERCONTROLDETAILS);
   mxcd.dwControlID=m_controlid;
   mxcd.cChannels=1;
   mxcd.cMultipleItems=0;
   mxcd.cbDetails=sizeof(MIXERCONTROLDETAILS_UNSIGNED);
   mxcd.paDetails=&mxcdVoume;
  
   mixerGetControlDetails((HMIXEROBJ)m_hMixer,&mxcd,
    MIXER_OBJECTF_HMIXER|MIXER_GETCONTROLDETAILSF_VALUE);
        m_cotrol.SetPos(mxcdVoume.dwValue);  
}
return 0L;
}

16.XP下静音

对话框初始化  

        HMIXER m_HMixer;
INT m_iMixerControlID;
MMRESULT mmr;
DWORD m_dwChannels;

MIXERLINE mxl;
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_BOOLEAN mxcd_b;

   
m_HMixer=NULL;
m_iMixerControlID=0;
m_dwChannels=0;

if (mixerGetNumDevs()<1)
{
   MessageBox("没有音频设备");
}
    
mixerOpen(&m_HMixer,0,0,0L,CALLBACK_NULL);
mxl.cbStruct=sizeof(MIXERLINE);
mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;


mixerGetLineInfo((HMIXEROBJ)m_HMixer,&mxl,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);
mxlc.cbStruct=sizeof(MIXERLINECONTROLS);
    mxlc.dwLineID=mxl.dwLineID;
mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls=1;
mxlc.cbmxctrl=sizeof(MIXERCONTROL);
mxlc.pamxctrl=&mxc;
mixerGetLineControls((HMIXEROBJ)m_HMixer,&mxlc,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);

m_iMixerControlID=mxc.dwControlID;
m_dwChannels=mxl.cChannels;

mxcd.cbStruct=sizeof(mxcd);
    mxcd.dwControlID=mxc.dwControlID;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(mxcd_b);
mxcd.paDetails=&mxcd_b;

mmr=mixerGetControlDetails((HMIXEROBJ)m_HMixer,&mxcd,0L);

CButton *P;
P=(CButton*)GetDlgItem(IDC_MUTE);
P->SetCheck(mxcd_b.fValue);


设置静音


void CSetMuteDlg::OnMute()
{
// TODO: Add your control notification handler code here
HMIXER m_HMixer;
INT m_iMixerControlID;
MMRESULT mmr;
DWORD m_dwChannels;

MIXERLINE mxl;
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
MIXERCONTROLDETAILS mxcd;
MIXERCONTROLDETAILS_BOOLEAN mxcd_b;

   
m_HMixer=NULL;
m_iMixerControlID=0;
m_dwChannels=0;

if (mixerGetNumDevs()<1)
{
   MessageBox("没有音频设备");
}

mixerOpen(&m_HMixer,0,0,0L,CALLBACK_NULL);
mxl.cbStruct=sizeof(MIXERLINE);
mxl.dwComponentType=MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;


mixerGetLineInfo((HMIXEROBJ)m_HMixer,&mxl,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINEINFOF_COMPONENTTYPE);
mxlc.cbStruct=sizeof(MIXERLINECONTROLS);
    mxlc.dwLineID=mxl.dwLineID;
mxlc.dwControlType=MIXERCONTROL_CONTROLTYPE_MUTE;
mxlc.cControls=1;
mxlc.cbmxctrl=sizeof(MIXERCONTROL);
mxlc.pamxctrl=&mxc;
mixerGetLineControls((HMIXEROBJ)m_HMixer,&mxlc,
   MIXER_OBJECTF_HMIXER|MIXER_GETLINECONTROLSF_ONEBYTYPE);

m_iMixerControlID=mxc.dwControlID;
m_dwChannels=mxl.cChannels;

mxcd.cbStruct=sizeof(mxcd);
    mxcd.dwControlID=m_iMixerControlID;
mxcd.cChannels=1;
mxcd.cMultipleItems=0;
mxcd.cbDetails=sizeof(mxcd_b);
mxcd.paDetails=&mxcd_b;

mmr=mixerGetControlDetails((HMIXEROBJ)m_HMixer,&mxcd,0L);

mxcd_b.fValue=!mxcd_b.fValue;
mmr=mixerSetControlDetails((HMIXEROBJ)m_HMixer,&mxcd,0L);
    if (m_HMixer)
  
   mixerClose(m_HMixer);
   

}

17:获取屏幕大小
int with= GetSystemMetrics(SM_CXFULLSCREEN);

int heigh= GetSystemMetrics(SM_CYFULLSCREEN);

通过上边两个函数获取的是显示屏幕的大小,及不包括任务栏等区域。


int   cx   =   GetSystemMetrics(   SM_CXSCREEN   );  
int   cy   =   GetSystemMetrics(   SM_CYSCREEN   );

这两个函数获取的是真正屏幕的大小。

用前两个函数获取的大小可能是1024*687    而用下边两个获取的就是1024*768

18.一个类访问控制另一个类中的变量控件

如果要在类CVDlg 访问控制类CPPDlg中的控件 CSliderCtrl。

首先在类CPPDlg中定义 CSliderCtrl m_sld;

然后在类CVDlg 中定义

CSliderCtrl* m_pSld;
CPPDlg* m_pDlg;

然后在类CVDlg的构造函数中定义:

m_pDlg=new CPPDlg;
m_pDlg->Create(IDD_PP);
m_pSld=&m_pDlg->m_sld;

这样就可以在类CVDlg中任何地方控制类CPPDlg中的控件 CSliderCtrl。

变量,控件都是这么做的。比较正宗的一种方式。


19.VISTA下控制屏幕的函数

Vista下如何用软件控制屏幕高层的API可以方便地控制屏幕的亮度、色温、对比度、显示区等。
初始化头文件

#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#pragma comment(lib,"dxva2.lib")

全局函数 (后面的函数都是调用这两个函数)

void FreePhysicalMonitor(DWORD npm, LPPHYSICAL_MONITOR ppm)
{
DestroyPhysicalMonitors(npm, ppm);
// Free the array.
free(ppm);
}

LPPHYSICAL_MONITOR GetPhysicalMonitor(DWORD *pnpm)
{
HMONITOR hMon = NULL;
hMon = MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY);
LPPHYSICAL_MONITOR ppm = NULL;
DWORD npm = 0;
BOOL bRet = GetNumberOfPhysicalMonitorsFromHMONITOR(hMon, &npm);
if (bRet) {
ppm = (LPPHYSICAL_MONITOR)malloc(npm * sizeof(PHYSICAL_MONITOR));
if (ppm) {
bRet = GetPhysicalMonitorsFromHMONITOR(hMon, npm, ppm);
if (!bRet) {
FreePhysicalMonitor(npm, ppm);
ppm = NULL;
npm = 0;
}
}
}
*pnpm = npm;
return ppm;
}

返回的是PHYSICAL_MONITOR数组,以下示例只是使用了第一个PHYSICAL_MONITOR元素。

1、调整屏幕前我们可以看看显示器支持什么功能
Vista提供的API是GetMonitorCapabilities(在有些显示器上虽然GetMonitorCapabilities调用失败,但仍然可以调整亮度等;在有些显示器上,从GetMonitorCapabilities返回的值看可以支持某些功能,但实际又不能。这些都另当别论)。

LPPHYSICAL_MONITOR ppm = 0;
ppm = GetPhysicalMonitor();
if (ppm) {
DWORD nmc = 0, nct = 0;
GetMonitorCapabilities(ppm->hPhysicalMonitor, &nmc, &nct);
CString str = _T("");
if (nmc & MC_CAPS_BRIGHTNESS) {
str += _T("Support brightness control\n");
}
if (nmc & MC_CAPS_COLOR_TEMPERATURE) {
str += _T("Support color temperature\n");
}
if (nmc & MC_CAPS_CONTRAST) {
str += _T("Support contrast\n");
}
.........
if (str == _T(""))
str = _T("Support None");
MessageBox(str);
FreePhysicalMonitor(npm, ppm);
}

2、如何调整亮度
LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
DWORD nMin = 0, nCur = 0, nMax = 0;
GetMonitorBrightness(ppm->hPhysicalMonitor, &nMin, &nCur, &nMax);
CString str;
str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);
MessageBox(str);
SetMonitorBrightness(ppm->hPhysicalMonitor, nMin);
Sleep(1000);
SetMonitorBrightness(ppm->hPhysicalMonitor, nMax);
Sleep(1000);
SetMonitorBrightness(ppm->hPhysicalMonitor, nCur);
Sleep(1000);
FreePhysicalMonitor(npm, ppm);
}

3、调色温

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_RED_GAIN, 50);
Sleep(500);
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_GREEN_GAIN, 49);
Sleep(500);
SetMonitorRedGreenOrBlueGain(ppm->hPhysicalMonitor, MC_BLUE_GAIN, 52);
MessageBox(_T("Set color temperature => Done"));

FreePhysicalMonitor(npm, ppm);
}

4、调对比度

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
DWORD nMin, nCur, nMax;
GetMonitorContrast(ppm->hPhysicalMonitor, &nMin, &nCur, &nMax);
CString str;
str.Format(_T("Min:%d, Cur:%d, Max:%d"), nMin, nCur, nMax);
MessageBox(str);
SetMonitorContrast(ppm->hPhysicalMonitor, nMin);
Sleep(1000);
SetMonitorContrast(ppm->hPhysicalMonitor, nMax);
Sleep(1000);
SetMonitorContrast(ppm->hPhysicalMonitor, nCur);
Sleep(1000);
FreePhysicalMonitor(npm, ppm);
}

5、查看显示器类型

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
TCHAR *descs[] = {
_T("Shadow-mask cathode ray tube (CRT)"),
_T("Aperture-grill CRT"),
_T("Thin-film transistor (TFT) display"),
_T("Liquid crystal on silicon (LCOS) display"),
_T("Plasma display"),
_T("Organic light emitting diode (LED) display"),
_T("Electroluminescent display"),
_T("Microelectromechanical display"),
_T("Field emission device (FED) display")
};
MC_DISPLAY_TECHNOLOGY_TYPE dtt;
GetMonitorTechnologyType(ppm->hPhysicalMonitor, &dtt);
CString str;
str.Format(_T("Technology type: %s"), descs[(int)dtt]);
MessageBox(str);
FreePhysicalMonitor(npm, ppm);
}

6、恢复出厂设置

LPPHYSICAL_MONITOR ppm = 0;
DWORD npm = 0;
ppm = GetPhysicalMonitor(&npm);
if (ppm) {
RestoreMonitorFactoryDefaults(ppm->hPhysicalMonitor);
FreePhysicalMonitor(npm, ppm);
}


20.OnHScroll的消息处理

if (pScrollBar->GetDlgCtrlID()==IDC_SLIDER_VOLUME)
   {
//m_Bspeed=TRUE;
int SliderInt=m_slider.GetPos();
        float fVolume = (float)SliderInt/100;
        hr = g_pEndptVol->SetMasterVolumeLevelScalar(fVolume, &g_guidMyContext);
        //ERROR_CANCEL(hr);
   
   }

21.用VC++2008写的控制台程序居然都无法在xp下运行,查了一下解决方法:


项目 -> 属性 -> 配置属性 -> 常规 -> MFC的使用 -> 选择"在静态库中使用mfc"

英文版:

Project->Property->configuration Properties->General->Use of MFC->选择Use MFC in a Static Library

22.全局函数访问对话框中的控件

CGloabkjDlg   *pDlg   =   (CGloabkjDlg   *)(AfxGetApp()->GetMainWnd());

23.格盘代码


char   *FormatW2K   =   "CMD.EXE";  
   
//这里我用H:盘,你自己要填入你想格式化的盘  
char   *FormatW2KParam   =   "/C   \"format.com   H:/force/q/u/x/V:MISC\"";  
   
//在后台执行格式化命令  
ShellExecute(NULL,"open",FormatW2K,FormatW2KParam,NULL,SW_HIDE);  

24.WINPE下关机代码
        char   *FormatW2K   =   "CMD.EXE";     
char   *RebootParam   =   "/C   \"wpeutil reboot \"";        
ShellExecute(NULL,"open",FormatW2K,RebootParam,NULL,SW_HIDE);

25.系统下关机代码:

    TOKEN_PRIVILEGES tp;
    HANDLE hToken;
    LUID luid;
    LPTSTR MachineName=NULL;
    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken ))
{
       // PERR("OpenProcessToken",GetLastError());
        return ;
}
    if(!LookupPrivilegeValue(MachineName, SE_SHUTDOWN_NAME, &luid))
{
      // PERR("LookupPrivilegeValue", GetLastError());
        return ;
}
    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),NULL, NULL ); //到这里,是取得权限///
    ExitWindowsEx(EWX_REBOOT,EWX_FORCE);

26.对话框加载工具栏

   1.添加成员变量 CToolBar m_WndToolBar

   2.在OnInitDialog() 中 CDialog::OnInitDialog();后添加
  
   if (!m_WndToolBar.CreateEx(this, TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_ALIGN_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS,CRect(4,4,0,0))||!m_WndToolBar.LoadToolBar(IDR_TOOLBAR1))
{
   TRACE0("未能创建工具栏\n");
   return -1;     
}
m_WndToolBar.ShowWindow(SW_SHOW);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);

27.设置热键
  
   现在开始处设置热键ID

#define HOTKEYA WM_USER+100
#define HOTKEYF WM_USER+101
#define HOTKEYJ WM_USER+102

在对话框初始化中注册热键服务

RegisterHotKey(m_hWnd,HOTKEYA,MOD_CONTROL,'A');
RegisterHotKey(m_hWnd,HOTKEYF,MOD_CONTROL,'F');
RegisterHotKey(m_hWnd,HOTKEYJ,MOD_CONTROL,'J');

在类中添加热键消息OnHotKey

void CSetHotKeyDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
    if((HOTKEYA==nHotKeyId)&&(nKey1==MOD_CONTROL)&&(nKey2=='A'))
{
     this->OnBnClickedButton1(); //此处设置热键调用的函数
}
if((HOTKEYF==nHotKeyId)&&(nKey1==MOD_CONTROL)&&(nKey2=='F'))
{
     this->OnBnClickedButton2(); //此处设置热键调用的函数
}
   if((HOTKEYJ==nHotKeyId)&&(nKey1==MOD_CONTROL)&&(nKey2=='J'))
{
     this->OnBnClickedButton3(); //此处设置热键调用的函数
}
CDialog::OnHotKey(nHotKeyId, nKey1, nKey2);
}


以上方法是在VS2008中设置的,较低版本需要自定义消息

afx_msg LRESULT OnHotKey(WPARAM wParam,LPARAM lParam); //消息声明

自定义消息

#define HOTKEYA WM_USER+100
#define HOTKEYF WM_USER+101
#define HOTKEYJ WM_USER+102

消息映射

ON_MESSAGE(WM_HOTKEY,OnHotKey)

在对话框初始化中注册热键服务

RegisterHotKey(m_hWnd,HOTKEYA,MOD_CONTROL,'A');
RegisterHotKey(m_hWnd,HOTKEYF,MOD_CONTROL,'F');
RegisterHotKey(m_hWnd,HOTKEYJ,MOD_CONTROL,'J');

添加函数

LRESULT CSetHotKeyDlg::OnHotKey(WPARAM wParam,LPARAM lParam)
{
if(wParam==HOTKEYEDIT)
   this->OnEdit();
if(wParam==HOTKEYLIST)
   this->OnList();
if(wParam==HOTKEYSET)
   this->OnSet();
return 0;
}


28.VC如何作出有动画效果的托盘图标

1在.h文件里定义变量:

protected:
HICON   m_hIcon;
HICON   m_hIconArray[4];//托盘区动画图标数组
int     m_nIconPos;     //当前托盘区显示图标

2.cpp文件中加入:

//主程序对话框类构造函数
CCDROMControlDlg::CCDROMControlDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCDROMControlDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CCDROMControlDlg)
m_nIconPos      = 0;    //托盘区动画图标从m_hIconArray[0]开始显示
//}}AFX_DATA_INIT

m_hIcon         = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

//加载托盘区动画图标
m_hIconArray[0] = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hIconArray[1] = AfxGetApp()->LoadIcon(IDI_ICON1);
m_hIconArray[2] = AfxGetApp()->LoadIcon(IDI_ICON2);
m_hIconArray[3] = AfxGetApp()->LoadIcon(IDI_ICON3);
}

//定时器消息处理函数,用来实现动画图标
void CCDROMControlDlg::OnTimer(UINT nIDEvent)
{
    NOTIFYICONDATA nc;
nc.cbSize = sizeof(NOTIFYICONDATA);
if(m_nIconPos==3)
    m_nIconPos=0;
nc.hIcon = m_hIconArray[m_nIconPos++];
nc.hWnd = m_hWnd;
lstrcpy(nc.szTip,"动画效果托盘图标");
nc.uCallbackMessage = WM_NOTIFYICON;           //自定义最小化托盘消息
nc.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nc.uID = IDC_NOTIFYICON;
Shell_NotifyIcon(NIM_MODIFY, &nc);
CDialog::OnTimer(nIDEvent);
}

只做这些托盘图标动画不会出来的 应该在前面做个 Shell_NotifyIcon(NIM_ADD, &nc);
动画才能出来。


posted @ 2012-06-11 00:41 无一 阅读(669) | 评论 (0)编辑 收藏

2012年6月9日

堆和栈的区别

 一、预备知识—程序的内存分配 
  一个由C/C++编译的程序占用的内存分为以下几个部分 
  1、栈区(stack)—   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其 
  操作方式类似于数据结构中的栈。 
  2、堆区(heap)   —   一般由程序员分配释放,   若程序员不释放,程序结束时可能由OS回 
  收   。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 
  3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的 
  全局变量和静态变量在一块区域,   未初始化的全局变量和未初始化的静态变量在相邻的另 
  一块区域。   -   程序结束后由系统释放。 
  4、文字常量区   —常量字符串就是放在这里的。   程序结束后由系统释放 
  5、程序代码区—存放函数体的二进制代码。 
  
  
  二、例子程序   
  这是一个前辈写的,非常详细   
  //main.cpp   
  int   a   =   0;   全局初始化区   
  char   *p1;   全局未初始化区   
  main()   
  {   
  int   b;   栈   
  char   s[]   =   "abc";   栈   
  char   *p2;   栈   
  char   *p3   =   "123456";   123456/0在常量区,p3在栈上。   
  static   int   c   =0;   全局(静态)初始化区   
  p1   =   (char   *)malloc(10);   
  p2   =   (char   *)malloc(20);   
  分配得来得10和20字节的区域就在堆区。   
  strcpy(p1,   "123456");   123456/0放在常量区,编译器可能会将它与p3所指向的"123456" 
  优化成一个地方。   
  }   
  
  
  二、堆和栈的理论知识   
  2.1申请方式   
  stack:   
  由系统自动分配。   例如,声明在函数中一个局部变量   int   b;   系统自动在栈中为b开辟空 
  间   
  heap:   
  需要程序员自己申请,并指明大小,在c中malloc函数   
  如p1   =   (char   *)malloc(10);   
  在C++中用new运算符   
  如p2   =   new   char[10];   
  但是注意p1、p2本身是在栈中的。   
  
  
  2.2   
  申请后系统的响应   
  栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢 
  出。   
  堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时, 
  会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表 
  中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的 
  首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。 
  另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部 
  分重新放入空闲链表中。   
  
  2.3申请大小的限制   
  栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意 
  思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有 
  的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将 
  提示overflow。因此,能从栈获得的空间较小。   
  堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储 
  的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小 
  受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。   
  
  
  
  2.4申请效率的比较:   
  栈由系统自动分配,速度较快。但程序员是无法控制的。   
  堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.   
  另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是 
  直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。 
    
  
  2.5堆和栈中的存储内容   
  栈:   在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可 
  执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈 
  的,然后是函数中的局部变量。注意静态变量是不入栈的。   
  当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地 
  址,也就是主函数中的下一条指令,程序由该点继续运行。   
  堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。   
  
  2.6存取效率的比较   
  
  char   s1[]   =   "aaaaaaaaaaaaaaa";   
  char   *s2   =   "bbbbbbbbbbbbbbbbb";   
  aaaaaaaaaaa是在运行时刻赋值的;   
  而bbbbbbbbbbb是在编译时就确定的;   
  但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。   
  比如:   
  #include   
  void   main()   
  {   
  char   a   =   1;   
  char   c[]   =   "1234567890";   
  char   *p   ="1234567890";   
  a   =   c[1];   
  a   =   p[1];   
  return;   
  }   
  对应的汇编代码   
  10:   a   =   c[1];   
  00401067   8A   4D   F1   mov   cl,byte   ptr   [ebp-0Fh]   
  0040106A   88   4D   FC   mov   byte   ptr   [ebp-4],cl   
  11:   a   =   p[1];   
  0040106D   8B   55   EC   mov   edx,dword   ptr   [ebp-14h]   
  00401070   8A   42   01   mov   al,byte   ptr   [edx+1]   
  00401073   88   45   FC   mov   byte   ptr   [ebp-4],al   
  第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到 
  edx中,再根据edx读取字符,显然慢了。   
  
  
  2.7小结:   
  堆和栈的区别可以用如下的比喻来看出:   
  使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就 
  走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自 
  由度小。   
  使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由 
  度大。

posted @ 2012-06-09 01:00 无一 阅读(140) | 评论 (0)编辑 收藏

仅列出标题  
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜