Xiaodong's profile千米马的厩PhotosBlogListsMore Tools Help

Blog


    杂想

    孤舟泛海,彼岸何岸?
    漫漠人生,今昔何昔?
    逝去的日子已不可再续,唯有回忆慢慢咀嚼,
    青春如汗水般不知不觉蒸发,留下的只是淡淡的咸,
    搭错了列车总有到站的一刻,我的列车还会经过这一站吗?

    失眠

    闹钟响了一遍又一遍,晕晕糊糊的爬起来,匆匆洗漱,匆匆赶班车,甚至没时间吃早饭!
    两周都如此,难道持续了一年的失眠消失了?这是好事还是坏事?
    怀念失眠的日子,可以很早起床,看书想事,悠悠然的洗漱吃早饭,然后再度着方步去上班。
    有所得必有怕失啦,多了睡眠时间却少了清醒的时间:)

    温习几个程序问题

    关键字:sizeof, extern "C", for循环的效率
     
    sizeof
     
    再仔细查阅了一下圣经--ISO标准,附1;
    首先,这个操作数求出来的是一个类型按byte计算的大小(The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type)
    个人觉得这个操作符完全可以看作是一种编译期行为,就是说运算在编译的时候已经完成了,编译器在编译后会把 sizeof(...)替换成一个常量(数据类型为标准中说的size_t);对那些在编译时无法确定大小的数据做sizeof操作都是错误的,或者说使用了编译时不能确定类型大小的数据都是不合法的;
    下面看看几种计算结果(假定int的大小是32bit):
    sizeof(2);  //2是int型, 结果为4
    sizeof(2*8); //2*8计算后的结果是int型, 结果仍是4
     
    char* s;
    sizeof(s);   //s 指针类型,结果是4
     
    char s[5];
    sizeof(s);  //s 是数组类型,其大小为5, 结果是5
     
    char* s = "Hello";
    sizeof(s)  //s 还是指针,千万别当成了数组, 结果还是4,
     
    char s[] = "Hello";
    sizeof(s);  //s 在这里可是数组, 所以结果是5;
     
    size_t  func(char s[])
    {
          return sizeof(s);   // 这里s又变成指针了(如果是数组,编译器怎么知道它大小?), 结果是4
    }
     
    size_t func(char s[])
    {
         return sizeof(s[5]); // 嗯,很容易搞混,这里s[5]已经是char类型了(就是s指向的第5个char),结果 
                                    // 是1
    }
     
    char s[5];
    sizeof(s[0]); //这个就比上面那个容易辨认些了,结果是1
     
    typedef struct _A
    {   int i;
        struct _A *next;
    }A;
    sizeof(A);   //A是一个structure,一个int 加一个指针,结果为8
    接上面的定义:
    A *a;
    sizeof(a);   //a 是一个指针,结果不说了
     
    typedef struct
    {
         char c;
         int   i;
    }B;
    sizeof(B);  //c是一个byte,i是4个byte, 但结果却不是5,这里有个指针对齐的问题.这也是标准中提到
                  // 的padding, 处理器访问int须是4的倍数地址访问,在这个结构里,c 占了一个字节, 后面3
                  // 个字节都不能做为i 的访问地址,所以编译器会在c的后面加上3个字节的padding, 这样,
                 // 结果应该是8;
     
    typedef struct
    {
        char c;
        int i;
        char c2;
    }C;
    sizeof(C); // 结果是12, c2后面也会被编译器加上3个padding, 确保紧跟这个结构后面的数据访问是
                 // 4字节对齐的
     
    typedef struct
    {
        char c;
        char c2;
        int i;
    }D;
    sizeof(D); //结果是8, 对char的访问地址可以是奇数.
     
    typedef struct
    {
        char c;
        short s16;
        char c2;
        int i;
    }E;
    sizeof(E); //结果是12, s16是short对它的访问可以是2倍数的地址,所以c后面填了一个byte的
                 // padding, c2后面填了3个 byte的padding.
     
    所以呢,在创建结构的时候有个原则,按数据大小来放置成员,能省不少空间.
     
    extern "C"
    嗯,标准里有较详细的描述, 抄袭在附2备查.
     
    for 循环的效率:
    这是曾经面试被问及的一个问题:
    for( i = 0; i<10; i++);
    for( i =10; i>0; i-- );
    哪个效率更高?看arm-
    GCC输出结果,+比-少一条指令,这样看应该是第一个的效率更高一些了。
    第一条输出的结果:
         mov r3, #9
    .L6:
         subs r3, r3, #1
         bpl .L6
    第二条输出的结果:
         mov r3, #10
    .L6:
         sub r3, r3, #1
         cmp r3, #0
         bgt .L6
     
    再看x86-gcc的输出结果也一样:
            movl      $9, %eax
            .p2align  2,,3
    .L6:
            decl       %eax
            jns         .L6
           
            movl      $10, %eax
            .p2align  2,,3
    .L11:
            decl       %eax
            test1     %eax, %eax
            jg         .L11
     
    [注]以上汇编是加了-O2优化选项的,如果未加优化选项,效率是一样的;
     
     
    附1: 下面的内容摘自:ISO/IEC 9899:1999 (E)
    6.5.3.4 The sizeof operator
       Constraints
    1 The sizeof operator shall not be applied to an expression that has function type or an
       incomplete type, to the parenthesized name of such a type, or to an expression that
       designates a bit-field member.
       Semantics
    2 The sizeof operator yields the size (in bytes) of its operand, which may be an
       expression or the parenthesized name of a type. The size is determined from the type of
       the operand. The result is an integer. If the type of the operand is a variable length array
       type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an
       integer constant.
    3 When applied to an operand that has type char, unsigned char, or signed char,
       (or a qualified version thereof) the result is 1. When applied to an operand that has array
       type, the result is the total number of bytes in the array.84) When applied to an operand
       that has structure or union type, the result is the total number of bytes in such an object,
       including internal and trailing padding.
    4 The value of the result is implementation-defined, and its type (an unsigned integer type)
       is size_t, defined in <stddef.h> (and other headers).
    5 EXAMPLE 1 A principal use of the sizeof operator is in communication with routines such as 
       storage allocators and I/O systems. A storage-allocation function might accept a size (in 
       bytes) of an object to
       allocate and return a pointer to void. For example:
           extern void *alloc(size_t);
           double *dp = alloc(sizeof *dp); 
       The implementation of the alloc function should ensure that its return value is aligned 
       suitably for conversion to a pointer to double.
    6 EXAMPLE 2 Another use of the sizeof operator is to compute the number of elements in an array:
          sizeof array / sizeof array[0]
    7 EXAMPLE 3 In this example, the size of a variable-length array is computed and returned from  a function:
         #include <stddef.h>
         size_t fsize3(int n)
        {
             char b[n+3]; // variable length array
             return sizeof b; // execution time sizeof
        }
        int main()
       {
            size_t size;
            size = fsize3(10); // fsize3 returns 13
            return 0;
       }
     
     
    附2: 下面的内容摘自:ISO/IEC 14882:1998(E)
    7.5 Linkage specifications
     
    linkagespecification:
       
    extern stringliteral { declarationseqopt}
        extern stringliteral declaration
    The stringliteral indicates the required language linkage. The meaning of the stringliteral is implementationdefined.A linkagespecification with a string that is unknown to the implementation is illformed. When the stringliteral in a linkagespecification names a programming language, the pelling of the programming language’s name is implementationdefined. [Note: it is recommended that the spelling be taken from the document defining that language, for example Ada (not ADA) and Fortran or FORTRAN (depending on the vintage). The semantics of a language linkage other than C++ or C are implementationdefined.]
    Every implementation shall provide for linkage to functions written in the C programming language, "C", and linkage to C++ functions, "C++".
    [Example:
       complex sqrt(complex); // C++ linkage by default
       extern "C" {
          double sqrt(double); // C linkage
       }
    —end example]
       
    Linkage specifications nest. When linkage specifications nest, the innermost one determines the language linkage. A linkage specification does not stablish a scope. A linkagespecification shall occur only in namespace scope (3.3). In a linkagespecification, the specified language linkage applies to the function types of all function declarators, function names, and variable names introduced by the declaration(s).
    [Example:
        extern "C" void f1(void(*pf)(int));
                                               // the name f1 and its function type have C language
                                               // linkage; pf is a pointer to a C function
        extern "C" typedef void FUNC();
        FUNC f2;                         // the name f2 has C++ language linkage and the
                                              // function’s type has C language linkage
        extern "C" FUNC f3;         // the name of function f3 and the function’s type
                                              // have C language linkage
        void (*pf2)(FUNC*);           // the name of the variable pf2 has C++ linkage and
                                              // the type of pf2 is pointer to C++ function that
                                              // takes one parameter of type pointer to C function
    —end example] A C language linkage is ignored for the names of class members and the member function type of class member functions.
    [Example:
        extern "C" typedef void FUNC_c();
        class C {
            void mf1(FUNC_c*);  // the name of the function mf1 and the member
                                           // function’s type have C++ language linkage; the
                                           // parameter has type pointer to C function
            FUNC_c mf2;           // the name of the function mf2 and the member
                                           // function’s type have C++ language linkage
            static FUNC_c* q;     // the name of the data member q has C++ language
                                           // linkage and the data member’s type is pointer to C function
            };
       
        extern "C" {
               class X {
                     void mf();                 // the name of the function mf and the member
                                                    // function’s type have C++ language linkage
                     void mf2(void(*)());     // the name of the function mf2 has C++ language
                                                    // linkage; the parameter has type pointer to C function
               };
        }
    —end example]
     
    If two declarations of the same function or object specify different linkagespecifications (that is, the linkagespecifications of these declarations specify different stringliterals), the program is illformed if the declarations appear in the same translation unit, and the one definition rule (3.2) applies if the declarations appear in different translation units. Except for functions with C++ linkage, a function declaration without a linkage specification shall not precede the first linkage specification for that function. A function can be declared without a linkage specification after an explicit linkage specification has been seen; the linkage explicitly specified in the earlier declaration is not affected by such a function declaration.
     
    At most one function with a particular name can have C language linkage. Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function. Two declarations for an object with C language linkage with the same name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same object. [Note: because of the one definition rule (3.2), only one definition for a function or object with C linkage may appear in the program; that is, such a function or object must not be defined in more than one namespace scope. For example,
       
    namespace A {
            extern "C" int f();
            extern "C" int g() { return 1; }
            extern "C" int h();
        }
        namespace B {
            extern "C" int f();                      // A::f and B::f refer to the same function
            extern "C" int g() { return 1; }     // illformed,the function g with C language linkage
                                                          // has two definitions
        }
        int A::f() { return 98; }                   // definition for the function f with C language linkage
        extern "C" int h() { return 97; }       // definition for the function h with C language linkage
                                                         // A::h and ::h refer to the same function
    —end note]
     
    Except for functions with internal linkage, a function first declared in a linkagespecification behaves as a function with external linkage.
    Example:
        extern "C" double f();
        static double f();      // error
    is illformed(7.1.1). ] The form of linkagespecification that contains a bracedenclosed declarationseq does not affect whether the contained eclarations are definitions or not (3.1); the form of linkagespecification directly containing a single declaration is treated as an extern specifier (7.1.1) for the purpose of determining whether the contained declaration is a definition.
    [Example:
          
    extern "C" int i;    // declaration
           extern "C" {
                 int i;             // definition
           }

    —end example] A linkagespecification directly containing a single declaration shall not specify a storage class.
    [Example:
        extern "C" static void f(); // error
    —end example]
     
    [Note: because the language linkage is part of a function type, when a pointer to C function (for example) is dereferenced, the function to which it refers is considered a C function. ]
    9 Linkage from C++ to objects defined in other languages and to objects defined in C++ from other languages is implementationdefined and languagedependent. Only where the object layout strategies of two language implementations are similar enough can such linkage be achieved.

    远方

    远方有多远?
    你的心有多大它就有多远.
    那我永远也到不了了?
    你就不能把心收小一点吗?
    我看不到边怎么收?
    你看不到边又怎么走?
    再走走说不定就看到了呢?
    知道吗?沙漠里的人,如果没有了方向参照,他永远只会在原地转圈.
    所以我一直跟着你啊.
    孩子,我累了,我发现自己一直在原地打转.
    不,我们每一天都不一样,我们不是在转圈!
    孩子,我们已经老了,走不了你那么快了,我们自己走的这个圈圈就是我们能走的最远距离了.我不希望你也跟着我们再划这个圈圈,你要比我们走得更远!
    没有了你们我不知道怎么走!
    孩子,我们就是你的参照,只要你走到我们看不到的地方,至少就比我们走的远,哪怕又是划圈,也是比我们更大的圈,或者是另一个完全不同的圈.
    我不想看不到你们!
    只要你闭上眼,我们就会在你身边.有句话叫条条大路通罗马,但其实很多人到不了,我们希望你是那个到达罗马的人,是那个找到自己远方的人!
     

    于是,我们一路走来,一步三回头,生怕哪一天真的就看不见他们了,我们不时的闭起眼,回想着他们的殷殷叮嘱.真的,他们就在我们身边.
     

    小的时候,看着远处的山,总想知道山的那边是什么?今天,已不知到了多少个山的那边的那边,虽然还没有到达心中的远方,但也还没有发现自己在划圈,累了,就闭起眼,想想他们,我相信,终有一天会到达心中的那个远方......

    夏日的回忆

      常常想起家乡夏日雨后的那种感觉,那是一种风雨过后的舒畅。清香的空气,深深的吸一口,闭上眼慢慢回味,感受自然的亲切;明朗的天空,湛蓝湛蓝的,一眼就看的透彻,让人恨不能就立刻插上翅膀去尽情翱翔;这时,你再背向太阳,看向那遥远的天际,一道七彩的拱桥横跨了半边天,仿佛要把远方的山梁连向更远的山梁。
        儿时的我们,总喜欢在夏日的雨中狂奔,没有任何理由,没有任何约定,一到下雨,伙伴们都冲了出来,任凭大人们在门口呼喝。每个人都无一例外的,作着骑摩托车的姿势,嘴里模拟着摩托车的叫声,呼着喊着跑着,直至耗尽气力,然后再回家被父母一段痛骂。
        盛夏,也是捉蜻蜓的好时候,荷田里起起落落到处是绿蜻蜓,捉蜻蜓是有讲究的:先捉一只母蜻蜓,用一根一米多长的细线拴住,手抓线的另一端,放飞蜻蜓,口中再念着咒语,摇晃着持线的手,用不了多久,就会有另一只绿蜻蜓飞来死死抱住被拴住的同伴,然后缓缓的把线往地上放,网兜跟上,一只蜻蜓就到手了!如法炮制,一会就能逮不少,再偷摘几朵荷花,把折散的花瓣撒的漫天飞舞,嘴里品尝着花芯,一路蹦跳着回家了。然而,夏雨总会在不知不觉间来临,没有任何征兆,一边是火辣辣的太阳,一边是豆大的雨点,还有在雨中顶着荷叶,喊着“鬼来了”的我们。弟弟是最小的,每次都哭着跑在最后,没办法,我也只能边跟着呼喊,边不紧不慢的跑在弟弟前面一点。

        雨后,伙伴们又都走出了家,呼吸着清香的空气,照着暖暖的阳光,坐在房前屋后看彩虹。有人说:那是龙在吸水,龙要喝饱了准备下一次下雨;有人说:那是仙人在搭桥,接那些在雨中淋湿了翅膀的仙女回家;弟弟说:哥,我长大了也要做一个,你带我到天上去玩!最后大家都没话说了,就指着彩虹说:“真漂亮!”