美祺's profileEden of HexagonPhotosBlogListsMore Tools Help

Blog


    July 29

    Hibernate 对视图的操作及配置

       也是这几天,在弄Hibernate的时候,发现对于视图的mapping往往做的很不够,如果这个视图里没有主键的话,那是无法搜出要的数据类的。呵呵,这个也就是平时说得给hibernate配视图:)不过,后面的myeclipse3.2平台上已经统一解决了这类问题,通过id类。这个针对的是过去eclipse3.1的平台而言,同时也让自己明白了hibernate的一些小脾气:)

    hibernate对视图的操作
          由于视图没有主键,所以在用hibernate对视图操作就需要做点处理了,网上搜了一通也没能找到相关文章,后来突然想到了myeclipse可以帮助生成hibernate的配置文件和对应的pojo代码。
          打开myeclipse,选择相关的视图,生成了配置文件和pojo类,发现pojo类生成了两个,而配置文件却一个,参看了配置文件和类,明白了是怎么回事。生成的配置文件通过了组合的方式生成,所以会对应两个类,一个类主要存放id信息,以个类存放对应的字段信息。
          下面是生成的类和配置文件:
    类:
    public class AllTablePb implements Serializable {

     // Fields
     private AllTablePbId id;

     // Property accessors
     public AllTablePbId getId() {
      return this.id;
     }

     public void setId(AllTablePbId id) {
      this.id = id;
     }
    }

    public class AllTablePbId implements java.io.Serializable {

     // Fields

     private String owner;

     private String tableName;

     private String columnName;

     private String dataType;

     private String pbcCnam;

     private String pbcCmnt;

     // Property accessors

     public String getOwner() {
      return this.owner;
     }

     public void setOwner(String owner) {
      this.owner = owner;
     }

     public String getTableName() {
      return this.tableName;
     }

     public void setTableName(String tableName) {
      this.tableName = tableName;
     }

     public String getColumnName() {
      return this.columnName;
     }

     public void setColumnName(String columnName) {
      this.columnName = columnName;
     }

     public String getDataType() {
      return this.dataType;
     }

     public void setDataType(String dataType) {
      this.dataType = dataType;
     }

     public String getPbcCnam() {
      return this.pbcCnam;
     }

     public void setPbcCnam(String pbcCnam) {
      this.pbcCnam = pbcCnam;
     }

     public String getPbcCmnt() {
      return this.pbcCmnt;
     }

     public void setPbcCmnt(String pbcCmnt) {
      this.pbcCmnt = pbcCmnt;
     }

    }

    配置文件:
    <hibernate-mapping>
     <class name="com.hhkj.workflow.bean.AllTablePb" table="V_ALLTAB_PB" schema="CANP">
      <composite-id name="id" class="com.hhkj.workflow.bean.AllTablePbId">
       <key-property name="owner" type="string">
        <column name="OWNER" length="30" />
       </key-property>
       <key-property name="tableName" type="string">
        <column name="TABLE_NAME" length="30" />
       </key-property>
       <key-property name="columnName" type="string">
        <column name="COLUMN_NAME" length="30" />
       </key-property>
       <key-property name="dataType" type="string">
        <column name="DATA_TYPE" length="106" />
       </key-property>
       <key-property name="pbcCnam" type="string">
        <column name="PBC_CNAM" length="30" />
       </key-property>
       <key-property name="pbcCmnt" type="string">
        <column name="PBC_CMNT" length="254" />
       </key-property>
      </composite-id>
     </class>
    </hibernate-mapping>
    这样就可以通过AllTablePb.getId()取得相关的信息。

    通过这样对视图的操作,同样也可以用到对于那些没有定义主键的表,操作方法是一样的。

     

    Java中Double的高精度问题及bigdecimal解决方式

        最近有空写了点老的J2EE的代码,发现有一个十分有意思的问题,当用Hibernate从数据库里把浮点数读取出来的时候做一些比如累加的工作,例如 summary 或者递减之类的,就会发现在最后的结果中会出现些许问题。
    如:3.41+5.2+56.2+23.3+... (这类两位小数的价钱),结果会出现103.00000000000001这种结果,但是人算的话反而会得出正常的数据。看样子double,float这类数据精度上来了还会有这类问题。
        于是,翻了点资料,在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。
        四舍五入
    我们的第一个反应是做四舍五入。Math类中的round方法不能设置保留几位小数,我们只能
    象这样(保留两位):
    public double round(double value){
        return Math.round(value*100)/100.0;
    }
    非常不幸,上面的代码并不能正常工作,给这个方法传入4.015它将返回4.01而不是4.02,
    如我们在上面看到的
    4.015*100=401.49999999999994
    因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算
    java.text.DecimalFormat也不能解决这个问题:
    System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
    输出是4.02

    BigDecimal
    在《Effective Java》这本书中也提到这个原则,float和double只能用来做科学计算或者
    是工程计算,在商业计算中我们要用 java.math.BigDecimal。BigDecimal一共有4个够造方
    法,我们不关心用BigInteger来够造的那两个,那么还有两个,它们是:
    BigDecimal(double val)
              Translates a double into a BigDecimal.
    BigDecimal(String val)
              Translates the String repre sentation of a BigDecimal into a
    BigDecimal.
    上面的API简要描述相当的明确,而且通常情况下,上面的那一个使用起来要方便一些。我
    们可能想都不想就用上了,会有什么问题呢?等到出了问题的时候,才发现上面哪个够造方
    法的详细说明中有这么一段:
    Note: the results of this constructor can be somewhat unpredictable. One might
    assume that new BigDecimal(.1) is exactly equal to .1, but it is actually equal
    to .1000000000000000055511151231257827021181583404541015625. This is so because
    .1 cannot be represented exactly as a double (or, for that matter, as a binary
    fraction of any finite length). Thus, the long value that is being passed in to
    the constructor is not exactly equal to .1, appearances nonwithstanding.
    The (String) constructor, on the other hand, is perfectly predictable: new
    BigDecimal(".1") is exactly equal to .1, as one would expect. Therefore, it is
    generally recommended that the (String) constructor be used in preference to
    this one.
     
    原来我们如果需要精确计算,非要用String来够造BigDecimal不可!在《Effective Java》
    一书中的例子是用String来够造BigDecimal的,但是书上却没有强调这一点,这也许是一个
    小小的失误吧。
     
    解决方案
    现在我们已经可以解决这个问题了,原则是使用BigDecimal并且一定要用String来够造。
    但是想像一下吧,如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造
    成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(
    BigDecimal)再转换为浮点数。你能够忍受这么烦琐的过程吗?下面我们提供一个工具类
    Arith来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:
    public static double add(double v1,double v2)
    public static double sub(double v1,double v2)
    public static double mul(double v1,double v2)
    public static double div(double v1,double v2)
    public static double div(double v1,double v2,int scale)
    public static double round(double v,int scale)
     
    附录
     
    源文件Arith.java:
    package com.common.util;
    import java.math.BigDecimal;
    /**
     * 由于Java的简单类型不能够精确的对浮点数进行运算,
     * 这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入。
     */
    public final class Arith {
     // 默认除法运算精度
     private static final int DEF_DIV_SCALE = 2;
     // 这个类不能实例化
     private Arith() {
     }
     /**
      * 提供精确的加法运算。
      *
      * @param v1 被加数
      * @param v2 加数
      * @return 两个参数的和
      */
     public static double add(double v1, double v2) {
      BigDecimal b1 = new BigDecimal(Double.toString(v1));
      BigDecimal b2 = new BigDecimal(Double.toString(v2));
      return b1.add(b2).doubleValue();
     }
     /**
      * 提供精确的减法运算。
      *
      * @param v1 被减数
      * @param v2 减数
      * @return 两个参数的差
      */
     public static double sub(double v1, double v2) {
      BigDecimal b1 = new BigDecimal(Double.toString(v1));
      BigDecimal b2 = new BigDecimal(Double.toString(v2));
      return b1.subtract(b2).doubleValue();
     }
     /**
      * 提供精确的乘法运算。
      *
      * @param v1 被乘数
      * @param v2 乘数
      * @return 两个参数的积
      */
     public static double mul(double v1, double v2) {
      BigDecimal b1 = new BigDecimal(Double.toString(v1));
      BigDecimal b2 = new BigDecimal(Double.toString(v2));
      return b1.multiply(b2).doubleValue();
     }
     /**
      * 提供(相对)精确的除法运算,当发生除不尽的情况时,
      * 精确到小数点以后10位,以后的数字四舍五入。
      *
      * @param v1 被除数
      * @param v2 除数
      * @return 两个参数的商
      */
     public static double div(double v1, double v2) {
      return div(v1, v2, DEF_DIV_SCALE);
     }
     /**
      * 提供(相对)精确的除法运算。
      * 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。
      *
      * @param v1 被除数
      * @param v2 除数
      * @param scale 表示表示需要精确到小数点以后几位。
      * @return 两个参数的商
      */
     public static double div(double v1, double v2, int scale) {
      if (scale < 0) {
       throw new IllegalArgumentException(
       "The scale must be a positive integer or zero");
      }
      BigDecimal b1 = new BigDecimal(Double.toString(v1));
      BigDecimal b2 = new BigDecimal(Double.toString(v2));
      return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
     }
     /**
      * 提供精确的小数位四舍五入处理。
      *
      * @param v 需要四舍五入的数字
      * @param scale 小数点后保留几位
      * @return 四舍五入后的结果
      */
     public static double round(double v, int scale) {
      if (scale < 0) {
       throw new IllegalArgumentException(
       "The scale must be a positive integer or zero");
      }
      BigDecimal b = new BigDecimal(Double.toString(v));
      BigDecimal one = new BigDecimal("1");
      return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
     }
    }
    呵呵,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 java.math.BigDecimal。这个才是解决的方式,我也试过了发现确实不错。不过话又说回来了,在.net里似乎没有发现有这类问题呀,能说他好么?我看未必,有时候封装的太好,功能太多,往往让人忘记了这些背后本来的面目:)
    July 27

    他们是这样一群男人(转载)

         他们是这样一群男人:没有钱,没有像样的球衣,找不到像样的训练场,甚至面临着各种威胁;但他们热爱自己的国家,在足球场上,他们誓死捍卫自己的尊严,拼尽全力,用胜利为苦难中的人民带去一丝快乐。
      他们有这样一句名言:“国内每天都有人战死,但从来没有人在足球场上为国家增添耻辱,就算死,也要有尊严地死!”
      伊拉克人视这群足球场上的战士为偶像,每当胜利降临,他们宁愿冒着生命的危险,也要走上街头,用枪炮来庆祝足球的胜利。对伊拉克人来说,快乐是一种奢侈,足球为他们带来这种奢侈,他们甘愿为之承受痛苦。
      快乐是奢侈
      对生活在战火和废墟中的伊拉克人民来说,快乐是一种奢侈。他们要面对别国球迷无法想像的生活困境,如缺水、缺电、缺燃料,恐怖威胁,人身安全无法保证等等。当他们得到快乐时,就像是得到了上天的恩赐。
      25日,当伊拉克男足历史性地闯入亚洲杯决赛,首都巴格达瞬间淹没在一片激烈的枪声中,冲锋枪和重机枪的枪声大作。这不是交火,而是疯狂的庆祝,伊拉克人用向天空鸣枪的方式来欢庆胜利。从伊拉克北部库德尔自治区到南部地区,欢庆的球迷随处可见,他们又唱又跳。
      整个伊拉克都沉浸在欢乐之中。对于灾难深重的伊拉克人来说,这快乐虽然短暂,却能给受伤的心带来些许慰藉。
      伊拉克主帅维埃拉说:“带给伊拉克人民快乐,是送给他们的最好礼物。”
      踢球是激情
      在伊拉克,球员是靠自己的激情在踢球。
      战火烧毁了伊拉克的一切体育设施,连足协的办公大楼都付之一炬,球员们没有足球、没有球衣、没有袜子、没有训练场……什么都没有。
      伊拉克球员大多在西亚国家的联赛和本国的联赛效力,像尤尼斯这样能够在卡塔尔加拉法比较专业和规范的足球俱乐部发展的极少,且国家队在国内集训时总是面临难找合适训练场地和备战时间仓促等问题,通常只有去伊拉克北部山区找一个相对安全、但条件相当简陋的地方训练。
      人民体育场还被美军占领着,俱乐部和球队都没有钱,球员在战争结束后没有领过一分钱的工资,他们都在靠自己的爱国激情踢球。
      就像所有伊拉克人一样,伊拉克球员也面临着各种危险:炸弹、流血、贫困、饥饿、绑架……因扑出韩国队点球而成为伊拉克英雄的门将阿巴斯在赛后就说:“目前在伊拉克踢球还是不安全的,即使伊拉克队夺得亚洲杯冠军,情况也不会改观。”
      长期以来,这些威胁一直存在。就在一个月前,在巴格达西边高速公路边的一个水沟里发现了13具尸体,他们都是伊拉克跆拳道运动员。今年二月,两名伊拉克球员在一次爆炸袭击中,一人身亡,一人断腿。去年,伊拉克国奥队球员加尼姆·库代耶尔遭遇了绑架,就连伊拉克奥委会主席也难逃此劫。
      然而,在如此恶劣的生存环境和集训条件下,伊拉克球员却一直在坚持,并屡创历史:2000年,伊拉克U19国青队获亚青赛亚军;2004年,伊拉克勇夺雅典奥运会铜牌;现在,他们又破天荒地闯入亚洲杯决赛。
      足球是未来
      伊拉克足球的胜利对伊拉克人来说还有一种重要的意义,他们把家园的重建精神寄托在伊拉克足球的重建之上。
      伊拉克足协主席侯赛因说:“在伊拉克,当足球比赛成为一件正常的事时,就意味着我们的生活已经回归了正常。”
      
      而此次伊拉克闯进亚洲杯决赛,将会引起全世界更多人的关注和帮助。  
      从地狱里出来的人,比别人更能体会生命的美好;一群死都不怕的人,足球场上还会怕啥。
      伊拉克球员身上,勃发着的是最原始的生命张力,像《红高粱》里的汉子,他们的激情不是像火,本身就是一团火。
     
    July 21

    FTP协议——相关参数

    最近弄了一点FTP的client端操作例程,由于在老的平台.net1.1上进行开发,只好使用最基本的socket通信去和Ftp服务通信,因此不得不调用这些FTP的命令,同时参照返回code码。可喜的是,.net2.0后的FLC里给FTP的操作专门提供了一系列方便的类和接口,呵呵,ftpclient好像是这个,省去了好多麻烦呢:)

    不过socket的协议接触下也不是什么坏事,至少还知道了通信这个层面的操作规范,算是有所小小收获吧。


    FTP ,尽管可以直接被终端用户使用,但其应用主要还是通过程序实现。FTP协议通过FTP控制帧使用TCP协议进行通信。FTP 控制帧即指 TELNET 交换信息,包含 TELNET 命令和选项。然而,大多数 FTP 控制帧是简单的 ASCII 文本,可以分为 FTP 命令或 FTP 消息。 FTP 消息是对 FTP 命令的响应,它由带有解释文本的应答代码构成。

    FTP命令命令  描述 
    ABOR 中断数据连接程序
    ACCT <account> 系统特权帐号
    ALLO <bytes>  为服务器上的文件存储器分配字节
    APPE <filename> 添加文件到服务器同名文件
    CDUP <dir path> 改变服务器上的父目录
    CWD <dir path> 改变服务器上的工作目录
    DELE <filename> 删除服务器上的指定文件
    HELP <command> 返回指定命令信息
    LIST <name> 如果是文件名列出文件信息,如果是目录则列出文件列表
    MODE <mode> 传输模式(S=流模式,B=块模式,C=压缩模式)
    MKD <directory> 在服务器上建立指定目录
    NLST <directory> 列出指定目录内容
    NOOP 无动作,除了来自服务器上的承认
    PASS <password> 系统登录密码
    PASV 请求服务器等待数据连接
    PORT <address> IP 地址和两字节的端口 ID
    PWD 显示当前工作目录
    QUIT 从 FTP 服务器上退出登录
    REIN 重新初始化登录状态连接
    REST <offset> 由特定偏移量重启文件传递
    RETR <filename> 从服务器上找回(复制)文件
    RMD <directory> 在服务器上删除指定目录
    RNFR <old path> 对旧路径重命名
    RNTO <new path> 对新路径重命名
    SITE <params> 由服务器提供的站点特殊参数
    SMNT <pathname> 挂载指定文件结构
    STAT <directory> 在当前程序或目录上返回信息
    STOR <filename> 储存(复制)文件到服务器上
    STOU <filename> 储存文件到服务器名称上
    STRU <type> 数据结构(F=文件,R=记录,P=页面)
    SYST 返回服务器使用的操作系统
    TYPE <data type> 数据类型(A=ASCII,E=EBCDIC,I=binary)
    USER <username>> 系统登录的用户名


    FTP响应码
    响应代码  解释说明 
    110 新文件指示器上的重启标记
    120 服务器准备就绪的时间(分钟数)
    125 打开数据连接,开始传输
    150 打开连接
    200 成功
    202 命令没有执行
    211 系统状态回复
    212 目录状态回复
    213 文件状态回复
    214 帮助信息回复
    215 系统类型回复
    220 服务就绪
    221 退出网络
    225 打开数据连接
    226 结束数据连接
    227 进入被动模式(IP 地址、ID 端口)
    230 登录因特网
    250 文件行为完成
    257 路径名建立
    331 要求密码
    332 要求帐号
    350 文件行为暂停
    421 服务关闭
    425 无法打开数据连接
    426 结束连接
    450 文件不可用
    451 遇到本地错误
    452 磁盘空间不足
    500 无效命令
    501 错误参数
    502 命令没有执行
    503 错误指令序列
    504 无效命令参数
    530 未登录网络
    532 存储文件需要帐号
    550 文件不可用
    551 不知道的页类型
    552 超过存储分配
    553 文件名不允许

    July 08

    Breakdown----Mariah Carey

         After God made the people, as while he'd like to be the company with them. However human kinds eventually build up hand-in-hand relations with Dog, which's ironically literal joke.
     
         Life's like a chocalate, u'd never know what taste the next time. "I'm trying to be nonchalant about it, u know, Jewel"
     
         <Breakdown> by Mariah Carey
     ( lyrics from lyric4u.com)
     
    WB:
    Break, breakdown. Steady breakin' me on down.
    Break, breakdown. Steady breakin' me on down.
    (MC: Oooooh)
    Break, breakdown. Steady breakin' me on down.
    Break, breakdown. Steady breakin' me on down.

    MC:
    You call yesterday to basically say
    That you care for me but that you're just not in love
    Immediately I pretended to beel similary
    And led you to believe I was O.K.
    To just walk away from the thing
    That's unyielding and sacred to me

    Well I guess I'm trying to be nonchalant about it
    And I'm going the extremes to prove I'm fine without you
    But in reality I'm slowly loosing my my mind
    Underneath the guise of a smile gradually I'm dying inside
    Friends ask me how I feel and I lie convincingly
    'Cause I don't want to reveal that fact that I'm suffering
    So I wear my disguise 'til I go home at night
    And turn down all the lights and then break down and cry

    So what do you do when somebody you're devoted to
    Suddenly just stops loving you and it seems they haven't got a clue
    Of the pain that rejection is putting you through
    Do you cling to your pride and sing "I will survive"
    (KB: Gotta get control and roll, roll, roll on.)
    Do you lash out and say: "How dare you leave this way"
    Do you hold on in vain as they just slip away

    Well I guess I'm trying to be nonchalant about it
    And I'm going the extremes to prove I'm fine without you
    But in reality I'm slowly loosing my my mind
    Underneath the guise of a smile gradually I'm dying inside
    Friends ask me how I feel and I lie convincingly
    'Cause I don't want to reveal that fact that I'm suffering
    So I wear my disguise 'til I go home at night
    And turn down all the lights and then break down and cry

    WB:
    Yeah, c'mon, yeah, c'mon c'mon.
    MC:
    Breakdown, breakdown.
    WB:
    Break, breakdown. Steady breakin' me on down.
    KB:
    Gotta get control and roll, roll, roll on.

    WB:
    Gonna break ya down, only if ya let it.
    Everyday crazy situations rockin' my mind tryin' to break me down,
    but I won't let it.
    Forget it, forget

    KB:
    I be feelin' like you're breakin' me down,
    kickin' me 'round, stressin' me out.
    I think I better go and get out and let me release some stress.

    WB:
    Don't ever wanna feel no pain, pain.
    Hopin' for the sun, but it looks like
    rain, rain, rain, rain.
    Lord, I just wanna maintain.

    KB:
    Yeah, I can feel the pressures, y'all,
    but nevertheless Krayzie won't fall.
    It's over.
    It's endin' here.

    Well I guess I'm trying to be nonchalant about it
    (WB: Break, breakdown. Steady breakin' me on down)
    And I'm going the extremes to prove I'm fine without you
    But in reality I'm slowly loosing my my mind
    Underneath the guise of a smile gradually I'm dying inside
    Friends ask me how I feel and I lie convincingly
    'Cause I don't want to reveal that fact that I'm suffering
    So I wear my disguise 'til I go home at night
    And turn down all the lights and then break down and cry

    July 07

    有趣的两道汇编题——Don't U Break Me down Today

        最近有位朋友正好要考到一些和汇编有关的题,所以打来这里要个解决方案。呵呵,我也是一下子来了兴趣,毕竟过去对汇编还是沉迷了一段时间,而且也在上机调ASM的时候成功的把一台PC搞歇了——乱调系统地址造成的(事后知道他们给拿去重装了)。Ok,题目也很简单,就两道,我写的时候加了比较多的注释,大概也是职业使然吧:)
     
       1。从strin单元开始有一串字符,,以* 为结束标志,要求字符串的长度,存入count单元,要求段说明和必要的伪指令。
    解答如下:
    name length_of_string
    data segment ;数据段定义
    string db 'dontubreakmedowntoday',2ah ;读取的字符串,2ah是*的ascii码且跟在string后
    count db ? ;定义count
    star equ 2ah ;定义star为*,方便后面比较
    data ends
    stack segment para stack'stack' ;堆栈段的定义(不是很重要,死记)
     db 100 dup(?)
    stack ends
    code segment ;代码段定义
     assume cs:code,ds:data,es:data,ss:stack ;定义各个段的用处
     
    start: proc far
    begin: push ds
     mov ax,0
     push ax
     mov ax,data
     mov ds,ax
     mov es,ax ;以上的是一个固定的初始化模式,照背就可以了
     
     lea di,string ;设置string串的地址指针
     mov dl,0  ;设置串的长度初始长度为0
     mov al,star  ;设置串的结束标记到al中
    again: scasb   ;搜索串(逐字节地)
     je done  ;找到结束标记,然后跳转到停止段
     inc dl  ;计数器加1
     jmp again  ;循环
    done: lea bx,count ;把count的地址入bx寄存器
     mov [bx],dl  ;把dl的赋给count
     ret
    start endp
    code ends
     end begin  ;game1 over
     
        2。从键盘上输入一行字符,要求第一个为space,否则end,如果是space,则开始接受键入字符,并保存在首地址为buffer的缓冲区,直到接受第二个space为止。(调用中断)
     
    解答如下:
     
     name input_string_store
    data segment ;数据段定义
    buffer db 100 dup(?) ;预存的缓冲区(100个大小,超过机器肯定崩)
    space equ 20h  ;定义空格,方便比较
    data ends
    stack segment para stack'stack' ;堆栈段的定义(不是很重要,死记)
     db 100 dup(?)
    stack ends
    code segment ;代码段定义
     assume cs:code,ds:data,es:data,ss:stack ;定义各个段的用处
      
    start: proc far
    begin: push ds
     mov ax,0
     push ax
     mov ax,data
     mov ds,ax
     mov es,ax ;以上的是一个固定的初始化模式,照背就可以了
      
     mov ah,1 ;将ah置1
       ;8086汇编中断21H系统功能调用全部子功能
       ;AH-01 键盘输入并回显 AL=输入字符
     int 21h ;调用中断,这两步是读取输入的步骤
     
     mov bl,al ;al中读取的字符放入bl中
     and bl,space ;比较bl和space字符
        ;如果相同,则进位标志C清0
     jc done  ;如果不同C=1,则跳转到结束,
        ;即第一个输入不是space,结束 
        ;第一个输入是space,则继续
        ;特别注意jc是根据c=1跳转的
     lea cx,buffer ;将buffer的首地址入cx寄存器
    again: mov ah,1  
     int 21h  ;调用中断,获得输入的字符
     mov bl,al  ;al中读取的字符放入bl中
     and bl,space ;比较bl和space字符
        ;如果相同,则进位标志C清0
        ;如果不同C=1
     jnc done  ;当第二次输入space时C=0跳转到结束
        ;否则继续
        ;特别注意jnc是根据c=0跳转的
     mov [cx],bl  ;将bl中的字符入cx当前指针
        ;指向的地址(即缓冲区)
     inc cx  ;cx的地址自增,指向buffer的下一个存放位置
     jmp again  ;循环
    done: ret
    start endp
    code ends
     end begin  ;game2 over