2005年01月28日

女主持人气势咄咄的问一个男嘉宾,你为什么那么在乎钱,男嘉宾说:“钱能买到一切!”
    现场的观众哗然了。
    男嘉宾微笑的说:“我们做个测试吧。”
    一个很简单的主题,你的一个仇人爱上了你的女友,现在想要你退出,你是一个正常的人,你爱自己的女友。那个男人愿意出一点钱来补偿你。
    所有的观众都很不屑这种论调,男人缓缓的开出了第一个价格“五万!”
    现场的观众松了口气,论点很集中:“五万,简直是瞧不起人,为了五万放弃了爱情?更主要的是放弃了自己的人格”所有的人都不约而同的否定了。
    男人接着开出了第二个价格“五十万!”
    现场的声音小了很多,一部分的人开始自己的计算了,在过了好大的一会儿,绝大多数的男人依然选择了否定,他身边的女友感动的看着他。只有少数的人接受了这五十万,其中的一个人说:“自己没有钱,父母苦了一辈子了,临老了生病没钱医治,为了父母,放弃了爱情吧。”
    男人接着开出了第三个价格“五百万!”
    现场更静了,男人的第一个动作都是看身边的女人,也许是在权衡什么。一半的男人沉默了,另一半的男人怯生生的说:“我要爱情。”身边的女友也有点呆住了,一个女孩子站起来说:“如果一个男人肯出五百万,我想我没有理由拒绝他。”沉默的男人选择了金钱,五百万可以买一套房子,一部车子,全家过上好日子,甚至可以开始自己的事业。一个男人说:“他是我的仇人,我有了这个五百万,我可以含辛茹苦,我可以报仇,我可以计划我所有的未来,当个真正主宰自己的男人。”一些女人看着身边的男人,若有所思。
    男人接着开出了第四个价格“五千万”
    全场哗然了,对于大多数的人,一辈子也挣不了这许多。女人说:“有肯为我一掷五千万的男人,他一定是爱我的,这样有钱又专一的男人,为什么不选择呢。”一个男人举手:“他真的肯付五千万?”在得到肯定的回答后,男人说:“爱情是无价的,但是我没有这个能力去照顾爱人,别人有,我应该放弃,并且我有了这许多的钱,我可以做很多有意义的事情,我可以成就事业,我可以帮助别人,这样的人生才有意义。”所有的人都深以为然。
    只有一个人依然选择了放弃,所有的人都用很奇怪的目光看他,他解释到:“我的爱情是无价的”,当问到他的女友是否感动的时候,女友说:“我虽然感动,但我更感动的是为了我付出自己五千万的人,而不是放弃别人的五千万,他的观点很可敬,但不现实。”
    嘉宾笑了笑,你们所有的人都选择了金钱。
    那个人还是以前的那个人,他的为人和评价只是因为钱的变化而完全改变了;爱情是无价的,也只是面对钱多钱少的时候。
    钱多就高尚了。所有无价的都是都是跟钱比较的,博物馆里的国宝,有钱了可以买,买不到了可以雇人偷和抢,再不行的话,可以发动战争,只要你有足够的钱。
    美国打伊拉克需要的是什么,钱;使用的是什么,还是钱,不过是一个以钱换钱的游戏罢了。
    所有的观众愕然了,想起自己的生活。
    想跳槽的时候,借口都不是钱,但都有一个理由:“我不在乎钱,但是我在乎工资,这代表我是否受尊重和我的价值。”是啊,相同的工作,一千块就侮辱了你,一万块就是尊重你,十次的侮辱等于尊重?
    嘉宾说,我不想解释为量变导致质变,爱情的质变不是钱多钱少的问题,而是,在你们之间叫的爱情如果通过交换就不叫了爱情。所以他拿钱换走的不是爱情,而是你的所有权,爱情已经走了,它依然无价!变质的爱情怎么还能叫爱情?
    所有的人性都有价格,而又无价,当你用金钱换取的时候,人性已经丢掉了,你售卖的价格已经和你原有的人性无关。
    嘉宾最后说了一句,我相信爱情,相信所有的人性,所以我努力的挣钱、爱钱。我只是不希望我的爱情和人性受到别人的金钱的考验罢了
    钱重要吗??

2005年01月26日

private void button1_Click(object sender, System.EventArgs e)
        
{
            
string strsearch=string.Format(@”SELECT MACAddress FROM Win32_NetworkAdapter WHERE ((MACAddress Is Not NULL)AND (Manufacturer <> ’Microsoft’)));

            System.Management.ManagementObjectSearcher msearch
=new ManagementObjectSearcher(); 
            msearch.Scope
=new ManagementScope(@”root\CIMV2);
            msearch.Query
=new ObjectQuery(strsearch);
            
int i=1;
            
try
            
{
                
if((msearch.Get().Count<1|| (msearch.Get()==null))
                
{
                    
this.listBox1.Items.Add(No MAC Address!);
                }

                
else
                
{
                    
foreach(System.Management.ManagementObject mymac in msearch.Get())
                    
{
                        
string str1=string.Format(MAC{0} address:{1},i.ToString(),mymac["MACAddress"].ToString());
                        
this.listBox1.Items.Add(str1);
                        i
++;
                    }

                }

            }

            
catch(Exception ex)
            
{
                
string msg=ex.Message.ToString();
                MessageBox.Show(
erro, msg);
            }


        }


WMI的应用


来源: maqiaos_cn
阅读:1476
日期:2004-7-30
作  者:maqiaos_cn
发表于:2003-1-16

    WMI(Windows Management Instrumentation)技术是微软提供的Windows下的系统管理工具。
通过该工具可以在本地或者管理客户端系统中几乎一切的信息。很多专业的网络管理工具都是
基于WMI开发的。该工具在Win2000以及WinNT下是标准工具,在Win9X下是扩展安装选项。本文
将介绍如何通过VB编程来访问WMI对象的编程。

   首先来看一个简单的通过WMI获取系统信息的范例,这个范例通过WMI对象获得系统中运行
的的进程:

Function Enum1() As String
    Dim WMI

    Set WMI = GetObject(“WinMgmts:”)
    Set objs = WMI.InstancesOf(“Win32_Process”)

    For Each obj In objs
        Enum1 = Enum1 + obj.Description + Chr(13) + Chr(10)
    Next
End Function

    在上面的代码中,首先通过  GetObject(“WinMgmts:”)获得WMI对象,在WMI对象下有很多的
子项,在这里我们通过WMI.InstancesOf(“Win32_Process”)获得系统中所有的进程列表子项。

    下面看一个完整的访问WMI对象的范例,这个范例获得计算机的信息。
    建立一个新工程,在Form1中添加一个TextBox控件以及一个CommandButton控件,在
CommandButton的Click事件中写入以下的代码:


Private Sub Command1_Click()
    Dim s, System, item
    Dim i As Integer

    Set System = GetObject(“winmgmts:”).InstancesOf(“Win32_ComputerSystem”)
    For Each item In System
        ‘List1.AddItem item.cputype
        s = “Computer Info” & vbCrLf
        s = s & “***********************” & vbCrLf
        s = s & “计算机名称: ” & item.name & vbCrLf
        s = s & “状态: ” & item.Status & vbCrLf
        s = s & “类型: ” & item.SystemType & vbCrLf
        s = s & “生产厂家: ” & item.Manufacturer & vbCrLf
        s = s & “型号: ” & item.Model & vbCrLf
        s = s & “内存: ~” & item.totalPhysicalMemory \ 1024000 & “mb” & vbCrLf
        s = s & “域: ” & item.domain & vbCrLf
        ‘s = s & “工作组” & item.Workgroup & vbCrLf ‘获得工作组和域的选项不能同时用

        s = s & “当前用户: ” & item.username & vbCrLf
        s = s & “启动状态” & item.BootupState & vbCrLf
        s = s & “该计算机属于” & item.PrimaryOwnerName & vbCrLf
        s = s & “系统类型” & item.CreationClassName & vbCrLf
        s = s & “计算机类类型” & item.Description & vbCrLf

        For i = 0 To 1  ‘这里假设安装了两个系统
            s = s & Chr(5) & “启动选项” & i & ” :” & item.SystemStartupOptions(i) _
                & vbCrLf
        Next i
    Next

    Text1.Text = s
End Sub

    运行程序,点击Command1,在textBox中就可以显示计算机的信息。

    在上面的代码中,程序通过GetObject(“winmgmts:”)获得WMI对象,然后获得下面的
Win32_ComputerSystem子项并通过访问Win32_ComputerSystem对象中的分项获得系统中的信息。
需要说明的是,并不是所有的系统都支持WMI,在有些系统中无法显示生产厂家等信息。

    现在的计算机以及网络组成十分复杂。例如系统硬件方面就有主板、硬盘、网卡… 。
软件方面有操作系统、系统中安装的软件、正在运行的进程等等。网络方面有域、工作组
等等。利用WMI可以访问上面的全部信息,但是如果向上面一样的利用分项来访问的话会很
麻烦。为此,WMI提供了一种类似SQL语句的查询语句,可以通过查询语句获得WMI对象下的子项。

    下面是一个遍历系统中安装的网卡并返回网卡MAC地址的代码:

Private Function MACAddress() As String

   Set objs = GetObject(“winmgmts:”).ExecQuery( _
      “SELECT MACAddress ” & _
      “FROM Win32_NetworkAdapter ” & _
      “WHERE ” & _
      “((MACAddress Is Not NULL) ” & _
      “AND (Manufacturer <> ” & _
      “‘Microsoft‘))”)

   For Each obj In objs
      MACAddress = obj.MACAddress
      Exit For
   Next obj
End Function

    上面的代码获得WMI对象,然后运行ExecQuery执行一个WMI查询语句获得安装的网卡并返回
网卡的MAC地址。

    WMI还支持事件处理,让程序可以处理系统事件,例如程序运行、关闭,可移动驱动器的插入、
取出等。下面是一个可以对系统中运行程序进行监控的程序。
    首先建立一个新工程,然后点击菜单的 project | references 项,在references列表中选中
Microsoft WMI Scripting Library将WMI对象库加入工程中。然后在Form1中加入一个ListBox控件,
然后在Form1中加入以下代码:


Option Explicit


Dim Locator As SWbemLocator
Dim Services As SWbemServices
Dim WithEvents StatusSink As SWbemSink

Private Sub KillEvents()
    StatusSink.Cancel
    Set StatusSink = Nothing
End Sub

Private Sub Form_Load()
    Dim Query As String

    Set StatusSink = New SWbemSink
    Set Locator = CreateObject(“WbemScripting.SWbemLocator”)
    Set Services = Locator.ConnectServer()

    Query = “SELECT * FROM __InstanceCreationEvent ”
    Query = Query + “WITHIN 1 ”
    Query = Query + “WHERE TargetInstance ISA ‘Win32_Process‘”

    Services.ExecNotificationQueryAsync StatusSink, Query
End Sub


Private Sub StatusSink_OnObjectReady(ByVal StatusEvent As SWbemObject, _
                                     ByVal EventContext As SWbemNamedValueSet)

    Dim arr
    Dim strQue As String
    Dim i As Integer

    List1.Clear
    arr = Split(StatusEvent.GetObjectText_, Chr(10))
    For i = LBound(arr) To UBound(arr)
        List1.AddItem arr(i)
    Next i
End Sub


Private Sub StatusSink_OnCompleted(ByVal HResult As WbemErrorEnum, _
                                   ByVal ErrorObject As SWbemObject, _
                                   ByVal EventContext As SWbemNamedValueSet)

    If HResult <> wbemErrCallCancelled Then
        ‘错误处理
    End If
End Sub



    在上面的程序中定义了一个SWbemSink对象StatusSink,然后建立一个SWbemServices对象Server,
并将StatusSink连接到Server对象上。这样就可以通过StatusSink监控程序的运行。
    运行程序,然后任意运行一个程序,在Form1的ListBox中就可以列出运行的程序的信息。

    WMI应用最强大的一面是可以通过WEB页面来实现远程管理。下面我们来建立一个HTML页面,该页面
可以实现向上面的VB程序一样动态监控系统中运行的程序。监控系统中程序运行的HTML代码如下:


<html>
<head>
<object ID=”mysink” CLASSID=
“CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223″></object>
</head>
<SCRIPT>
function window.onload()
{
  var locator = new ActiveXObject (“WbemScripting.SWbemLocator”);
  var service = locator.ConnectServer();
  szQuery = “SELECT * FROM __InstanceCreationEvent “;
  szQuery += “WITHIN 1 “;
  szQuery += “WHERE TargetInstance ISA ‘Win32_Process‘”;
  service.ExecNotificationQueryAsync(mysink,szQuery);
}
</SCRIPT>
<script FOR=”mysink” EVENT=”OnObjectReady(obj, objAsyncContext)”>
  document.all.info.innerHTML += obj.TargetInstance.Name + “<br>”;
</script>
<body>
<span ID=”info”></span>
</body>
</html>


    保存代码为Htm后缀的页面文件。双击打开网页,然后运行一个程序,在网页上就可以列出
运行的程序的文件名。

    以上简要的介绍了一下WMI的应用,实际上WMI对象的操作是十分复杂,功能也是很强大的,例如
你可以通过WMI在服务器上监控整个局域网上的计算机、向局域网上的计算机批量安装软件(例如杀
毒软件)。通过页面远程访问服务器,控件服务器运行程序,添加用户等。关于更多的WMI的应用,
读者可以访问MSDN上WMI开发的主页:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmistart_5kth.asp

获取更多信息。



    以上程序在Win2000专业版下编写。

2004年12月20日

 一、自动登录不求人

  和Windows 2000 Server一样,Windows Server 2003进入系统时也要求同时按下“Ctrl+Alt+Del”组合键,然后输入用户名和密码,才能登录。在这里我们可以通过设置让它自动登录,方法就是照搬笔者在Windows 2000上曾经使用过的方法,按下“WIN+R”组合键,打开“运行”对话框,输入“regedit”,按确定后会弹出熟悉的注册表编辑器。打开“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows_NT\CurrentVersion\Winlogon”分支,新建字符串值AutoAdminLogon,将该项的值设为1,再新建字符串值DefaultPassword,将该项设为你的管理员密码。这样就一切OK了。

或者用命令行:control userpasswords2

四、谁说不能CS

  很多CS玩家抱怨Windows Server 2003中CS游戏不能玩,这是因为Windows Server 2003中默认禁用了声音服务,以及DirectX加速,我们可以把它们一一开启。首先打开“服务”窗口,找到并双击“Windows Audio”,将它设置为自动。然后在桌面上单击右键,选择“属性→设置→高级→疑难解答”,将其中的“硬件加速”滚动条拖到最右侧。最后打开“运行”对话框,输入dxdiag,确定后弹出“DirectX诊断工具,进入“显示”页面,分别点击DirectDraw、Direct3D和AGPTexture三个按钮启用加速。  

  五、我想关机就关机

  Windows Server 2003中关机是需要“充分”理由的,要取消它很容易。按下“WIN+R”组合键,打开“运行”对话框,输入gpedit.msc,打开“组策略编辑器”,选择“本地计算机策略→计算机配置→管理模板→系统”,接着双击右侧窗口中的“显示关闭事件跟踪程序”,最后在“设置”选项卡中“已禁用”即可。

  这些设置完后,你就可以尽情地享受Windows Server 2003给你带来的快乐了。

2004年12月17日

CONST

.一般应用
1.const
修饰各种变量的用法.
   a.
取代define
     #define D_INT 100
     #define D_LONG 100.29
     ………
     const int D_INT = 100;
     const D_INT = 100;     //
如果定义的int类型,可省略int.
     const long D_LONG = 100.29;
     ………
     const int& a = 100;
     const
替代define虽然增加分配空间,可它却保证了类型安全.
    
C标准中,const定义的数据相当于全局的,C++中视声明的位置而定.
   b.
修饰指针相关的变量
    
以三组简单的定义示意:
     Group1:  
     int a = 0;   
     const int* b = &a;————  [1]               
     int const *b = &a;————  [2]                    
     const int* const b = &a;—- [4]  
         
     Group2: 
     const char *p = “const”;————–[1]
     char const *p = “const”;————–[2]  
     char* const p = “const”;————–[3]  
     const char * const p = “const”;—-[4]     
    
     Group3:
      int a=0;
        const int &b = a;—————[1]
     int const &b = a;—————[2] 
     int & const b = a;————–[3]  //—>
修饰引用时,const被忽略
     const int & const b = a;—–[4]
    
总结:
     1.
如果const位于星号左侧,const用来修饰指针所指向的变量,
      
即指针指向的为不可变的.
     2.
如果const位于星号右侧,const就是修饰指针本身,即指针本身是
      
不可变的.
      
因此,[1][2]的情况相同,指针所指向内容不可变(const放在变量
      
声明符的位置无关),
      
这种情况下不允许对内容进行更改,如不能*a = 3 ;
     3.[3]
中指针本身是不可变的,而指针所指向的内容是可变的,这种情况
      
下不能对指针本身
      
进行更改操作,a++是错误的
     4.[4]
中指针本身和指向的内容均为常量.(引用特殊:引用在使用增加
      
遇义时,增加它代表的变量.所以qualifiers on reference are ignoredv.
      
延伸点:
      
注意示例:
       1.const int& reference = 1000;
       2.char* p = “const”
         char*& q ;
  
2.const
在函数环境下的各种应用
  
常用法示例如下:
   const A&  _Fun(const  A& _in);  //
修饰引用型传入参数
   // A  _Fun(const A& _in);
   //A& _Fun(const A& _in);
   //
上面的两种,在函数内部有特殊的步骤,这里不详提了…..
 
   const  A*  _Fun( const  A* _in);   //
修饰指针型传入参数
   void _Fun( ) const;   //
修饰class成员函数
   const  A&  _Fun(A& _in );  //
修饰返回值
   const A & operator(const A& _in);  //
同时修饰传入参数和返回值

   a.修饰参数
    
void _Fun(const A* _in) void _Fun(const A& _in);
    
它们被修饰后,在函数执行期间行为特性同于上面的讲解,
    
注意:这不会改变原来数据的是否是const的属性.

   b.修饰函数返回值
    const A&  _Fun( )
    const A*   _Fun( );
   
注意:由于生命期不同步的问题,不可将局部的变量的指针或引用返回(static除外).
   
另外,传出来的视情况,代表不同的意思…
   
对于A&返回类型,你若将之赋与其它变量,那么它实际执行的是将返回的变量
    (
或引用)代表的数据赋出..而你若将其它值赋予之,那么被赋予的是变量或引
   
用代表的数据. const A& 一般是防止之做为左值被赋值.

    这个地方还有很多的细节问题(譬如在连续赋值、返回的临时对象的处理、
   
重载的const和非cosnt运算符等等),读者自己在实践中需要多多总结.

使用可变(mutable)成员隐藏实现细节

作者: Builder.com

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。


对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

volatile关键字

  volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型
  如:int,char,long……也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候,结构或者
  类的所有成员都会被视为volatile.

  使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要
  例如:
  int i;
  i = i + 3;
  无论如何,总是会有一小段时间,i会被放在一个寄存器中,因为算术运算只能在寄存器中进行。一般来说,volatitle
  关键字适用于行与行之间,而不是放在行内。

  我们先来实现一个简单的函数,来观察一下由编译器产生出来的汇编代码中的不足之处,并观察volatile关键字如何修正
  这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)


 oid getKey(char* pch)
  {
  while (*pch == 0)
  ;
  }

  当你在VC开发环境中将最优化选项都关闭之后,编译这个程序,将获得以下结果(汇编代码)



  ;       while (*pch == 0)
  $L27
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[ebp]
  ; Load the character into the EAX register
  movsx eax, BYTE PTR [eax]
  ; Compare the value to zero
  test eax, eax
  ; If not zero, exit loop
  jne $L28
  ;
  jmp $L27
  $L28
  ;}

  这段没有优化的代码不断的载入适当的地址,载入地址中的内容,测试结果。效率相当的低,但是结果非常准确

  现在我们再来看看将编译器的所有最优化选项开关都打开以后,重新编译程序,生成的汇编代码,和上面的代码

  比较一下有什么不同



  ;{
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[esp-4]
  ; Load the character into the AL register
  movsx al, BYTE PTR [eax]
  ; while (*pch == 0)
  ; Compare the value in the AL register to zero
  test al, al
  ; If still zero, try again
  je SHORT $L84
  ;
  ;}



使用可变(mutable)成员隐藏实现细节

作者: Builder.com

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。


对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

volatile关键字

  volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型
  如:int,char,long……也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候,结构或者
  类的所有成员都会被视为volatile.

  使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要
  例如:
  int i;
  i = i + 3;
  无论如何,总是会有一小段时间,i会被放在一个寄存器中,因为算术运算只能在寄存器中进行。一般来说,volatitle
  关键字适用于行与行之间,而不是放在行内。

  我们先来实现一个简单的函数,来观察一下由编译器产生出来的汇编代码中的不足之处,并观察volatile关键字如何修正
  这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)


 oid getKey(char* pch)
  {
  while (*pch == 0)
  ;
  }

  当你在VC开发环境中将最优化选项都关闭之后,编译这个程序,将获得以下结果(汇编代码)



  ;       while (*pch == 0)
  $L27
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[ebp]
  ; Load the character into the EAX register
  movsx eax, BYTE PTR [eax]
  ; Compare the value to zero
  test eax, eax
  ; If not zero, exit loop
  jne $L28
  ;
  jmp $L27
  $L28
  ;}

  这段没有优化的代码不断的载入适当的地址,载入地址中的内容,测试结果。效率相当的低,但是结果非常准确

  现在我们再来看看将编译器的所有最优化选项开关都打开以后,重新编译程序,生成的汇编代码,和上面的代码

  比较一下有什么不同



  ;{
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[esp-4]
  ; Load the character into the AL register
  movsx al, BYTE PTR [eax]
  ; while (*pch == 0)
  ; Compare the value in the AL register to zero
  test al, al
  ; If still zero, try again
  je SHORT $L84
  ;
  ;}



.一般应用
1.const
修饰各种变量的用法.
   a.
取代define
     #define D_INT 100
     #define D_LONG 100.29
     ………
     const int D_INT = 100;
     const D_INT = 100;     //
如果定义的int类型,可省略int.
     const long D_LONG = 100.29;
     ………
     const int& a = 100;
     const
替代define虽然增加分配空间,可它却保证了类型安全.
    
C标准中,const定义的数据相当于全局的,C++中视声明的位置而定.
   b.
修饰指针相关的变量
    
以三组简单的定义示意:
     Group1:  
     int a = 0;   
     const int* b = &a;————  [1]               
     int const *b = &a;————  [2]                    
     const int* const b = &a;—- [4]  
         
     Group2: 
     const char *p = “const”;————–[1]
     char const *p = “const”;————–[2]  
     char* const p = “const”;————–[3]  
     const char * const p = “const”;—-[4]     
    
     Group3:
      int a=0;
        const int &b = a;—————[1]
     int const &b = a;—————[2] 
     int & const b = a;————–[3]  //—>
修饰引用时,const被忽略
     const int & const b = a;—–[4]
    
总结:
     1.
如果const位于星号左侧,const用来修饰指针所指向的变量,
      
即指针指向的为不可变的.
     2.
如果const位于星号右侧,const就是修饰指针本身,即指针本身是
      
不可变的.
      
因此,[1][2]的情况相同,指针所指向内容不可变(const放在变量
      
声明符的位置无关),
      
这种情况下不允许对内容进行更改,如不能*a = 3 ;
     3.[3]
中指针本身是不可变的,而指针所指向的内容是可变的,这种情况
      
下不能对指针本身
      
进行更改操作,a++是错误的
     4.[4]
中指针本身和指向的内容均为常量.(引用特殊:引用在使用增加
      
遇义时,增加它代表的变量.所以qualifiers on reference are ignoredv.
      
延伸点:
      
注意示例:
       1.const int& reference = 1000;
       2.char* p = “const”
         char*& q ;
  
2.const
在函数环境下的各种应用
  
常用法示例如下:
   const A&  _Fun(const  A& _in);  //
修饰引用型传入参数
   // A  _Fun(const A& _in);
   //A& _Fun(const A& _in);
   //
上面的两种,在函数内部有特殊的步骤,这里不详提了…..
 
   const  A*  _Fun( const  A* _in);   //
修饰指针型传入参数
   void _Fun( ) const;   //
修饰class成员函数
   const  A&  _Fun(A& _in );  //
修饰返回值
   const A & operator(const A& _in);  //
同时修饰传入参数和返回值

   a.修饰参数
    
void _Fun(const A* _in) void _Fun(const A& _in);
    
它们被修饰后,在函数执行期间行为特性同于上面的讲解,
    
注意:这不会改变原来数据的是否是const的属性.

   b.修饰函数返回值
    const A&  _Fun( )
    const A*   _Fun( );
   
注意:由于生命期不同步的问题,不可将局部的变量的指针或引用返回(static除外).
   
另外,传出来的视情况,代表不同的意思…
   
对于A&返回类型,你若将之赋与其它变量,那么它实际执行的是将返回的变量
    (
或引用)代表的数据赋出..而你若将其它值赋予之,那么被赋予的是变量或引
   
用代表的数据. const A& 一般是防止之做为左值被赋值.

    这个地方还有很多的细节问题(譬如在连续赋值、返回的临时对象的处理、
   
重载的const和非cosnt运算符等等),读者自己在实践中需要多多总结.

使用可变(mutable)成员隐藏实现细节

作者: Builder.com

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。


对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

volatile关键字

  volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型
  如:int,char,long……也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候,结构或者
  类的所有成员都会被视为volatile.

  使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要
  例如:
  int i;
  i = i + 3;
  无论如何,总是会有一小段时间,i会被放在一个寄存器中,因为算术运算只能在寄存器中进行。一般来说,volatitle
  关键字适用于行与行之间,而不是放在行内。

  我们先来实现一个简单的函数,来观察一下由编译器产生出来的汇编代码中的不足之处,并观察volatile关键字如何修正
  这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)


 oid getKey(char* pch)
  {
  while (*pch == 0)
  ;
  }

  当你在VC开发环境中将最优化选项都关闭之后,编译这个程序,将获得以下结果(汇编代码)



  ;       while (*pch == 0)
  $L27
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[ebp]
  ; Load the character into the EAX register
  movsx eax, BYTE PTR [eax]
  ; Compare the value to zero
  test eax, eax
  ; If not zero, exit loop
  jne $L28
  ;
  jmp $L27
  $L28
  ;}

  这段没有优化的代码不断的载入适当的地址,载入地址中的内容,测试结果。效率相当的低,但是结果非常准确

  现在我们再来看看将编译器的所有最优化选项开关都打开以后,重新编译程序,生成的汇编代码,和上面的代码

  比较一下有什么不同



  ;{
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[esp-4]
  ; Load the character into the AL register
  movsx al, BYTE PTR [eax]
  ; while (*pch == 0)
  ; Compare the value in the AL register to zero
  test al, al
  ; If still zero, try again
  je SHORT $L84
  ;
  ;}



使用可变(mutable)成员隐藏实现细节

作者: Builder.com

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。

键字 mutable 是一个奇怪的修饰符(specifier),它只能够用于一个类的非静态数据成员。下面我将讨论 mutable 的语义和用法,但是首先我要解释一下 C++ 对象模型的一个关键概念。


对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

对象的状态

一个对象的状态由其非静态数据成员的值构成,因此,修改一个数据成员将会改变整个对象的状态。将一个成员函数声明为 const 能够保证它不会改变对象的状态。

然而在一些情况下,对象的逻辑状态与基物理状态之间可能有差别。例如,对于一个表示绘画图像的对象就存在这种情况。如果图像还没有更改,那么我们就认为其状态没有发生变化。然而,从底层实现方面来说,如果大对象在一段时间没有活动,那么它们的内存通常会被交换到一个文件中。交换一个图像并不会真地影响其状态,但是对象的一些数据成员可能会发生变化,在这里可能会发生变化的是指针、标志位等。

在用户调用一个诸如 Redraw() 之类的 const 成员函数时,他们并不关心这个函数在内部是如何实现的。从他们的角度来说,这个函数并不改变对象的逻辑状态,因此被声明为 const。Redraw() 有可能修改对象的物理状态这一事实是一个他们不应该关心的实现细节。例如:

int Image::Redraw() const
{
 if (isLoaded==false)
 {
  //..read image data from a disk into a local buffer
  isLoaded=true; //changing a data member’s value
 }
  //..paint image in the screen
}

class Image

可变(mutable)数据成员

如果尝试编译这段代码,你会得到一个编译错误。虽然 Redraw() 声明为 const,但是它修改了一个数据成员。解决这个编译错误的方法是将 isLoaded 声明为一个 mutable 数据成员:

class Image
{
public:
 int Redraw() const;
 //..
private:
 mutable bool isLoaded;//can be changed by a const function
};

不像普通的数据成员,const 成员函数可以修改 mutable 数据成员。

Mutable 数据成员的使用看上去像是骗术,因为它能够使 const 函数修改对象的数据成员。然而,明智地使用 mutable 关键字可以提高代码质量,因为它能够让你向用户隐藏实现细节,而无须使用不确定的东西,比如 const_cast<>。

volatile关键字

  volatile是c/c++中一个鲜为人知的关键字,该关键字告诉编译器不要持有变量的临时拷贝,它可以适用于基础类型
  如:int,char,long……也适用于C的结构和C++的类。当对结构或者类对象使用volatile修饰的时候,结构或者
  类的所有成员都会被视为volatile.

  使用volatile并不会否定对CRITICAL_SECTION,Mutex,Event等同步对象的需要
  例如:
  int i;
  i = i + 3;
  无论如何,总是会有一小段时间,i会被放在一个寄存器中,因为算术运算只能在寄存器中进行。一般来说,volatitle
  关键字适用于行与行之间,而不是放在行内。

  我们先来实现一个简单的函数,来观察一下由编译器产生出来的汇编代码中的不足之处,并观察volatile关键字如何修正
  这个不足之处。在这个函数体内存在一个busy loop(所谓busy loop也叫做busy waits,是一种高度浪费CPU时间的循环方法)


 oid getKey(char* pch)
  {
  while (*pch == 0)
  ;
  }

  当你在VC开发环境中将最优化选项都关闭之后,编译这个程序,将获得以下结果(汇编代码)



  ;       while (*pch == 0)
  $L27
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[ebp]
  ; Load the character into the EAX register
  movsx eax, BYTE PTR [eax]
  ; Compare the value to zero
  test eax, eax
  ; If not zero, exit loop
  jne $L28
  ;
  jmp $L27
  $L28
  ;}

  这段没有优化的代码不断的载入适当的地址,载入地址中的内容,测试结果。效率相当的低,但是结果非常准确

  现在我们再来看看将编译器的所有最优化选项开关都打开以后,重新编译程序,生成的汇编代码,和上面的代码

  比较一下有什么不同



  ;{
  ; Load the address stored in pch
  mov eax, DWORD PTR _pch$[esp-4]
  ; Load the character into the AL register
  movsx al, BYTE PTR [eax]
  ; while (*pch == 0)
  ; Compare the value in the AL register to zero
  test al, al
  ; If still zero, try again
  je SHORT $L84
  ;
  ;}



2004年12月02日

链表与数组的区别
A 从逻辑结构来看
A-1. 数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当     数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。


A-2. 链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、     删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)



B 从内存存储来看
B-1. (静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小
B-2. 链表从堆中分配空间, 自由度大但是申请管理比较麻烦.


堆和栈的区别


solost 2004 1009 发表


一、预备知识程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1栈区(stack—   编译器(Compiler)自动分配释放 ,存放函数的参数值局部变量的值等。其操作方式类似于数据结构中的栈。
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);
分配得来得1020字节的区域就在堆区。
strcpy(p1, “123456″); 123456\0
放在常量区,编译器可能会将它与p3所指向的“123456″优化成一个地方。
}


二、堆和栈的理论知识
2.1
申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在cmalloc函数
p1 = (char *)malloc(10);
C++中用new运算符
p2 = (char *)malloc(10);
但是注意p1p2本身是在栈中的。


2.2
申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3
申请大小的限制
栈:在Windows, 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。


2.4
申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5
堆和栈中的存储内容
栈: 在函数调用时,(1) 第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址(2) 然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,(3) 然后是函数中的局部变量。 注意: 静态变量是不入栈的。
当本次函数调用结束后,(1) 局部变量先出栈,(2) 然后是参数,(3) 最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

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
小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。



深度优先搜索与广度优先搜索算法有何区别呢?
  通常深度优先搜索法不全部保留结点,扩展完的结点从数据库中弹出删去,这样,一般在数据库中存储的结点数就是深度值,因此它占用空间较少。所以,当搜索树的结点较多,用其它方法易产生内存溢出时,深度优先搜索不失为一种有效的求解方法。
  广度优先搜索算法,一般需存储产生的所有结点,占用的存储空间要比深度优先搜索大得多,因此,程序设计中,必须考虑溢出和节省内存空间的问题。但广度优先搜索法一般无回溯操作,即入栈和出栈的操作,所以运行速度比深度优先搜索要快些

2004年11月30日

摘自http://www.cnblogs.com/roky/

net stop iisadmin /y
net start w3svc

net stop mssqlserver
net start mssqlserver

IISRESET.EXE (C) Microsoft Corp. 1998-1999

用法:
iisreset [computername]

/RESTART 停止然后重新启动所有 Internet 服务。
/START 启动所有 Internet 服务。
/STOP 停止所有 Internet 服务。
/REBOOT 重新启动计算机。
/REBOOTONERROR 如果在启动、停止或重新启动 Internet 服务时出错,则重新启
动计算机。
/NOFORCE 如果试图正常停止服务失败,不强制终止 Internet 服务。
/TIMEOUT:val 指定等待 Internet 服务的成功停止的超时值(以秒为单位)。
如果已指定 REBOOTONERROR 参数,超时后可以重新启动计算机。
服务重新启动的默认值为 20 秒,停止为 60 秒,计算机重新启
动为 0 秒。
/STATUS 显示所有 Internet 服务的状态。
/ENABLE 启用本地系统上 Internet 服务的重新启动。
/DISABLE 禁用本地系统上 Internet 服务的重新启动。

2004年11月20日

#include “memory.h”

memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘\0’;例:char a[100];memset(a, ‘\0′, sizeof(a));

memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。

strcpy就只能拷贝字符串了,它遇到’\0′就结束拷贝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。

strcpy
 原型:extern char *strcpy(char *dest,char *src);
 用法:#include <string.h>
 功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
 说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
       返回指向dest的指针。
memcpy
 原型:extern void *memcpy(void *dest, void *src, unsigned int count);
 用法:#include <string.h>
 功能:由src所指内存区域复制count个字节到dest所指内存区域。
 说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。
memset
 原型:extern void *memset(void *buffer, int c, int count);
 用法:#include <string.h>
 功能:把buffer所指内存区域的前count个字节设置成字符c。
 说明:返回指向buffer的指针。


ASSERT()是干什么用的

  ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。例如,变量n在程序中不应该为0,如果为0可能导致错误,你可以这样写程序:
    ……
    ASSERT( n != 0);
    k = 10/ n;
    ……
    ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
    assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。


system(”pause”);
系统的暂停程序,按任意键继续,屏幕会打印,“按任意键继续。。。。。” 省去了使用getchar();

2004年11月18日

assert是为了处理程序中很难扑捉到的错误。其作用是在程序发生错误的时候使程序终止执行。
assert是C++语言预先定义好的,使用断言时必须假头文件<cassert>
事实上assert不紧可以终止程序,还可以提示更加详细的提示信息。一般提示用户那个文件的那行出了问题。
由于assert是在某种错误的情况下终止正在执行的程序,并指出错误的信息。所以_
在某种意义上assert等同于return
原则上assert对于程序开发阶段很有用,但在程序开发结束,已经投入使用后,应该取消代码中的所有_
断言,但在大型软件开发结束后很难做到把断言全部去掉,所以采用一种方式让断言语句尽管存在,
可是不起作用,方法是在#include<assert>语句前加#define NDEBUG
assert(expression);函数很简单,如果expression是TURE或者1,则不产生任何反映
如果expression是FALSE或者0,则跳出正在执行的模块,并提示错误信息。


ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。例如,变量n在程序中不应该为0,如果为0可能导致错误,你可以这样写程序:
    ……
    ASSERT( n != 0);
    k = 10/ n;
    ……
    ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
    assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。

    

此问题由李海回答。

2004年11月13日





发信人: Capa (卡帕 — 天道酬勤), 信区: Job
标 题: 毕业五年有感,给年轻人的一点忠告 zz
发信站: 日月光华 (2004年10月15日01:46:36 星期五), 站内信件

发信人: richwinner (投资顾问), 信区: Career
标 题: 毕业五年有感,给年轻人的一点忠告!
发信站: BBS 水木清华站 (Wed Oct 13 11:11:40 2004)

1.合作。不要随便与人合作,与人合作要考虑好利与弊。如果有想法尽快去干,
一个人努力的干,卖命的干。干到差不了,有资本了,可以与人短期性的合作。与
人合作目标要明确。

2.努力。工作要努力,随随便便过日子过四五年也是过,稍微努力的过四五年
也是过,努力的过四五年也是过,何不努力好好的干。如果努力的过好毕业后的四
五年,这对我们以后的人生很有帮助。

3.吃苦耐劳。不要怕吃苦。在创业阶段,我们要的是名气,是经验,有时候在
保本的情况下可以以低价策略来和别人竞争。我们出卖的是点脑力活,力气活,年
轻人,睡一觉起来什么都恢复了。

4.目标。生活要有目标,不仅仅是事业(赚钱)的目标,其他方面也要有目标,
如爱情方面的目标,健康方面的目标。家庭方面的目标。各个目标都要重视。只赚
了钱,不算人生的成功。

5.虚心学习。多与比自己大的人(长辈)/ 成功人事。交流学习,要虚心听取
/ 认真分析他们的意见和建议,一面自己以后走弯路。

6.了解社会。多了解社会。多实践。多分析某些社会现象的因果厉害关系。认
真分析身边发生某些事情。正视社会的阴暗面。分析社会上某些不良风气,不要清
高自傲。也不要随波逐流。某些时候半事情,也需要这方面的帮助。

7.自由。出来外面做事情,关键是自由,愉快,能学到知识。每走一步都要分
析,不要因某一小点利益限制了自己的自由。

8.计划。给自己定一个五年计划,十年规划。每季度做什么事情,每个月做什
么事情。甚至每天做什么事情,有个计划,有个目标比较好。不要每天混混恶恶。
几年后你会发现,几年来一直没有目标,什么也没有做成。

9.胆量。你是工人的子弟,或是农民的儿子。难免思想狭隘。不要盲目。盲从。
也不要胆小怕事。

多锻炼,大胆去做事情,只要不违法。大胆去做。即使失败了,也为下次积累
经验。” 商场如战场” ,这句话一点不假。想想,在战场上,不是你死就是我亡。

10. 谋略。人生活在社会上,就是要用自己的智慧谋略和别人都智斗勇。即使
某些人的成功,不是电视小说里说的那么偶然的。有其必然性。生活中不玩点小技
巧(犯法的不做。害人的不做)。哪能那么容易就成功。

11. 不要害怕贫穷。也许你家里没有几十万是百万。大胆的去做事情,不要怕
贫穷。即使我们事情做失败了,我们大不了回到起点。还是穷人。

12. 学习。不断充实自己。学习新的知识。多学点技能。为以后作准备。也可
作为以后的娱乐消遣。如:驾驶技术,炒菜做饭,毛笔字等。

13. 惜时。如果以上你都做了,我估计你的时间过得很快。我常听某某人说:
” 这一辈子,就象昨天今天一样。” ,毛泽东说:” 天地转,光阴迫。一万年太久,
只争朝夕。”.” 三是八年过去弹指一挥间。” ,不要因碌碌无为而悔恨!!!


爱从一个微笑开始, 在热吻中延伸,却随眼泪逝去…
※ 来源:·日月光华 bbs.fudan.edu.cn·[FROM: 218.81.218.45]
※ 修改:·Capa 於 10月15日02:15:21 修改本文·[FROM: 218.81.218.45]

※ 转寄:·日月光华 bbs.fudan.edu.cn·[FROM: 10.85.24.224]

2004年11月10日

二 .类与结构的差别

  1.值类型与引用类型


  结构是值类型:值类型在堆栈上分配地址,所有的基类型都是结构类型,例如:int 对应System.int32 结构,string 对应 system.string 结构 ,通过使用结构可以创建更多的值类型


  类是引用类型:引用类型在堆上分配地址


  堆栈的执行效率要比堆的执行效率高,可是堆栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基类型对待的小对象,而类处理某个商业逻辑


  因为结构是值类型所以结构之间的赋值可以创建新的结构,而类是引用类型,类之间的赋值只是复制引用


  注:


  1.虽然结构与类的类型不一样,可是他们的基类型都是对象(object),c#中所有类型的基类型都是object


  2.虽然结构的初始化也使用了New 操作符可是结构对象依然分配在堆栈上而不是堆上,如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用


  2.继承性


  结构:不能从另外一个结构或者类继承,本身也不能被继承,虽然结构没有明确的用sealed声明,可是结构是隐式的sealed .


  类:完全可扩展的,除非显示的声明sealed 否则类可以继承其他类和接口,自身也能被继承


  注:虽然结构不能被继承 可是结构能够继承接口,方法和类继承接口一样
3.内部结构:


  结构:


  没有默认的构造函数,但是可以添加构造函数


  没有析构函数


  没?abstract 和 sealed(因为不能继承)


  不能有protected 修饰符


  可以不使用new 初始化


  在结构中初始化实例字段是错误的


  类:


  有默认的构造函数


  有析构函数


  可以使用 abstract 和 sealed


  有protected 修饰符


  必须使用new 初始化


  三.如何选择结构还是类


  讨论了结构与类的相同之处和差别之后,下面讨论如何选择使用结构还是类:


  1.堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些


  2.结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低。


  3.在表现抽象和多级别的对象层次时,类是最好的选择


  4.大多数情况下该类型只是一些数据时,结构时最佳的选择


补充c结构和c++类的区别:
C++ CLASS里的构造函数和析构函数可以在一个对象创建和销毁的时候自动执行的.
结构主要是针对特定的数据进行组织的,而类是具体对象的各种属性等的集合