• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            MyMSDN

            MyMSDN記錄開發(fā)新知道

            #

            [C++]namespace&using keyword

            有時(shí)候我們可以用namespace來(lái)組織命名空間。

            有時(shí)候我們又希望將一些較深層次的類變成我們比較容易訪問(wèn)的對(duì)象。

            下面的代碼提供了一種簡(jiǎn)單的示例來(lái)滿足這樣的需求。

            1、用namespace來(lái)組織各個(gè)類的層級(jí)關(guān)系。

            2、用using關(guān)鍵字,將深層次結(jié)構(gòu)暴露到較外層。

            //============================================================================
            // Name        : namespace.cpp
            // Author      : Volnet
            // Version     :
            // Copyright   : reserve by volnet@tom.com
            // Description : namespace in C++, Ansi-style
            //============================================================================
            
            #include <iostream>
            
            namespace volnet {
                namespace extensions {
                    class _Console {
                    public:
                        void WriteLine(std::string);
                    };
                }
                using extensions::_Console;
            }
            using namespace volnet;
            _Console Console;
            
            void
            _Console::WriteLine(std::string s) {
                std::cout << s << std::endl;
            }
            
            using namespace std;
            
            int main() {
                Console.WriteLine(std::string("I'm volnet!"));
                return 0;
            }

            posted @ 2010-03-29 13:28 volnet 閱讀(1422) | 評(píng)論 (0)編輯 收藏

            Eclipse CDT 的無(wú)效路徑

            Eclipse CDT在修改內(nèi)建的Includes的時(shí)候(右鍵項(xiàng)目,點(diǎn)擊屬性,C/C++ General),右邊的Delete按鈕將不可用,也就是說(shuō),無(wú)法刪除它們。

            image

            這個(gè)Includes將會(huì)影響到解決方案項(xiàng)目樹下的Includes。如果這些Includes實(shí)際不存在的時(shí)候,編譯后將出現(xiàn)警告(不影響正常使用),但是非常令人發(fā)指。

            image

            如何刪掉它們呢?

            在工作區(qū)對(duì)應(yīng)的.metadata文件夾下,{workspace}\.metadata\.plugins\org.eclipse.cdt.make.core\{projectname},找到你自己的項(xiàng)目,并搜索一些關(guān)鍵字,比如你實(shí)際不存在的路徑,將對(duì)應(yīng)的節(jié)點(diǎn)刪除即可。保存后重新打開Eclipse,它們應(yīng)該就不復(fù)存在了。

            引用:http://zadecn.spaces.live.com/Blog/cns!85EE31844454E642!337.entry?sa=661235468
            使用Eclipse + CDT,我經(jīng)常使用一些環(huán)境變量設(shè)置include path.同時(shí)當(dāng)我把這個(gè)工程文件在機(jī)器之間移植的時(shí)候,我一般會(huì)修改這些環(huán)境變量的值,非常奇怪的是,Eclipse仍然會(huì)保留那些沒有使用的,無(wú)效的 include path.
            這雖然不會(huì)造成嚴(yán)重的錯(cuò)誤,但是會(huì)生成警告,非常令人討厭.我一直查找刪除這些無(wú)效的include path的方法,終于查找到這樣的一句話:
            I've seen this problem too, old paths are never deleted. To manually fix the file you need to move/delete the ${projectname}.sc file found under ${workspace}/.metadata/.plugins/org.eclipse.cdt.make.core
            這樣就可以了.

            posted @ 2010-03-26 13:24 volnet 閱讀(1571) | 評(píng)論 (0)編輯 收藏

            boost::tuple

            boost::tuple<derived> tup4;
            boost::tuple<base> tup5;
            tup5 = tup4;
            tup4.get<0>().test();
            tup5.get<0>().test(); // 丟失多態(tài)性
            derived d; boost::tuple<derived*> tup6(&d); boost::tuple<base*> tup7; tup7 = tup6; tup6.get<0>()->test(); tup7.get<0>()->test(); // 恢復(fù)多態(tài)性(方法1) boost::tuple<derived&> tup8(d); boost::tuple<base&> tup9(tup8);
            // tup9 = tup8; 不能使用該方法,因?yàn)闊o(wú)法對(duì)引用賦值。
            tup8.get<0>().test(); tup9.get<0>().test(); // 恢復(fù)多態(tài)性(方法2)
            /*
             * tuple.cpp
             *
             *  Created on: 2010-3-25
             *      Author: GoCool
             */
            #include <stdlib.h>
            #include <iostream>
            #include <boost/tuple/tuple.hpp>
            #include <boost/tuple/tuple_io.hpp>
            #include "../header/baseClass.h"
            
            using namespace std;
            class X {
              X();
            public:
              X(std::string){}
            };
            class Y {
              Y(const Y&);
            public:
              Y(){}
            };
            class A {
            };
            bool operator==(A, A) { std::cout << "All the same to me..."; return true; }
            void f(int i);
            
            void cut_off_rule(void);
            int main(void){
                // add a new tuple
                boost::tuple<int,double,std::string>   triple(42, 3.14, "My first tuple!");
                int a = triple.get<0>();
                ++a;
                cout << a << endl;
                cout << triple << endl;
            
                cut_off_rule();
            
                boost::tuple<int, double> pair = boost::make_tuple(21, 22.5);
                cout << pair << endl;
            
                cut_off_rule();
            
                int pair_element_1 = -1;
                double pair_element_2 = -1;
                boost::tie(pair_element_1, pair_element_2) = pair;
            
                cout << pair_element_1 << "," << pair_element_2 << endl;
            
                cut_off_rule();
            
                boost::tuple<int,std::string,derived> tup1(-5,"Tuples");
                boost::tuple<unsigned int,std::string,base> tup2;
                tup2=tup1;
                tup2.get<2>().test();
                std::cout << "Interesting value: " << tup2.get<0>() << '\n';
                const boost::tuple<double,std::string,base> tup3(tup2);
                // Description    Resource    Path    Location    Type
                // assignment of read-only location    tuple.cpp    boost_tuple/src    45    C/C++ Problem
                // tup3.get<0>()=3.14;
            
                cut_off_rule();
            
                boost::tuple<X,X,X> obj = boost::tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")); // ok
            
                cut_off_rule();
            
                double dNum = 5;
                boost::tuple<double&> numTuple(dNum);               // ok
            
                // boost::tuple<double&>(dNum+3.14);          // error: cannot initialize
                                                // non-const reference with a temporary
            
                boost::tuple<const double&>(dNum+3.14);    // ok, but dangerous:
                                                // the element becomes a dangling reference
                cut_off_rule();
            
                // char arr[2] = {'a', 'b'};
                // boost::tuple<char[2]>(arr); // error, arrays can not be copied
                // boost::tuple<char[2], Y>(arr, Y()); // error, neither arrays nor Y can be copied
            
                boost::tuple<char[2], Y>();       // ok
            
                cut_off_rule();
            
                boost::tuple<void (*)(int)> pFTuple1 = boost::make_tuple(&f);
                pFTuple1.get<0>()(10);
            
                boost::tuple<void (*)(int)> pFTuple2 = boost::make_tuple(boost::ref(f));
                pFTuple2.get<0>()(20);
            
                boost::tuple<void (&)(int)> pFTuple3(f);
                pFTuple3.get<0>()(30);
            
                boost::tuple<boost::tuple<void (&)(int)> > pFTuple4(f);
                pFTuple4.get<0>().get<0>()(40);
            
                cut_off_rule();
            
                // boost::tuple<int, char> stdPairToTuple = std::make_pair(1, 'a');
            
                cut_off_rule();
            
                boost::tuple<std::string, int, A> t1(std::string("same?"), 2, A());
                boost::tuple<std::string, long> t2(std::string("same?"), 2);
                boost::tuple<std::string, long> t3(std::string("different"), 3);
                // t1 == t2;        // true
            
                cut_off_rule();
            
                int i; char c;
                boost::tie(i, c) = std::make_pair(1, 'a');
                cout << i << " " << c << endl;
            
                cut_off_rule();
            
                boost::tie(boost::tuples::ignore, c) = std::make_pair(1, 'a');
                cout << c << endl;
            
                cut_off_rule();
            
                int myX = -1;
                double myY = -2;
                boost::tuple<int, double> f2(2);
                boost::tie(myX, myY) = f2; // #2
                cout << "myX = " << myX << ", myY = " <<myY << endl;
            }
            void cut_off_rule(void) {
                cout << "-----------------------------------" << endl;
            }
            
            void f(int i) {
                cout << "f(" << i << ")" << endl;
            }
            
            
            

            tuple是boost庫(kù)中一個(gè)類似標(biāo)準(zhǔn)std::pair庫(kù)庫(kù),但pair只能支持兩種元素,而tuple則可以支持大于兩種的。

            更多詳解:http://www.boost.org/doc/libs/1_42_0/libs/tuple/doc/tuple_users_guide.html

            以下內(nèi)容直接引自原文:


             

            Boost C++ LibrariesBoost C++ Libraries

            “...one of the most highly regarded and expertly designed C++ library projects in the world.” — Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

            C++ 
Boost

            The Boost Tuple Library

            A tuple (or n-tuple) is a fixed size collection of elements. Pairs, triples, quadruples etc. are tuples. In a programming language, a tuple is a data object containing other objects as elements. These element objects may be of different types.

            Tuples are convenient in many circumstances. For instance, tuples make it easy to define functions that return more than one value.

            Some programming languages, such as ML, Python and Haskell, have built-in tuple constructs. Unfortunately C++ does not. To compensate for this "deficiency", the Boost Tuple Library implements a tuple construct using templates.

            Table of Contents

            1. Using the library
            2. Tuple types
            3. Constructing tuples
            4. Accessing tuple elements
            5. Copy construction and tuple assignment
            6. Relational operators
            7. Tiers
            8. Streaming
            9. Performance
            10. Portability
            11. Acknowledgements
            12. References
            More details

            Advanced features (describes some metafunctions etc.).

            Rationale behind some design/implementation decisions.

            Using the library

            To use the library, just include:

            #include "boost/tuple/tuple.hpp"

            Comparison operators can be included with:

            #include "boost/tuple/tuple_comparison.hpp"

            To use tuple input and output operators,

            #include "boost/tuple/tuple_io.hpp"

            Both tuple_io.hpp and tuple_comparison.hpp include tuple.hpp.

            All definitions are in namespace ::boost::tuples, but the most common names are lifted to namespace ::boost with using declarations. These names are: tuple, make_tuple, tie and get. Further, ref and cref are defined directly under the ::boost namespace.

            Tuple types

            A tuple type is an instantiation of the tuple template. The template parameters specify the types of the tuple elements. The current version supports tuples with 0-10 elements. If necessary, the upper limit can be increased up to, say, a few dozen elements. The data element can be any C++ type. Note that void and plain function types are valid C++ types, but objects of such types cannot exist. Hence, if a tuple type contains such types as elements, the tuple type can exist, but not an object of that type. There are natural limitations for element types that cannot be copied, or that are not default constructible (see 'Constructing tuples' below).

            For example, the following definitions are valid tuple instantiations (A, B and C are some user defined classes):

            tuple<int>
            tuple<double&, const double&, const double, double*, const double*>
            tuple<A, int(*)(char, int), B(A::*)(C&), C>
            tuple<std::string, std::pair<A, B> >
            tuple<A*, tuple<const A*, const B&, C>, bool, void*>

            Constructing tuples

            The tuple constructor takes the tuple elements as arguments. For an n-element tuple, the constructor can be invoked with k arguments, where 0 <= k <= n. For example:

            tuple<int, double>() 
            tuple<int, double>(1)
            tuple<int, double>(1, 3.14)

            If no initial value for an element is provided, it is default initialized (and hence must be default initializable). For example.

            class X {
            X();
            public:
            X(std::string);
            };

            tuple<X,X,X>() // error: no default constructor for X
            tuple<X,X,X>(string("Jaba"), string("Daba"), string("Duu")) // ok

            In particular, reference types do not have a default initialization:

            tuple<double&>()                // error: reference must be 
            // initialized explicitly

            double d = 5;
            tuple<double&>(d) // ok

            tuple<double&>(d+3.14) // error: cannot initialize
            // non-const reference with a temporary

            tuple<const double&>(d+3.14) // ok, but dangerous:
            // the element becomes a dangling reference

            Using an initial value for an element that cannot be copied, is a compile time error:

            class Y { 
            Y(const Y&);
            public:
            Y();
            };

            char a[10];

            tuple<char[10], Y>(a, Y()); // error, neither arrays nor Y can be copied
            tuple<char[10], Y>(); // ok

            Note particularly that the following is perfectly ok:

            Y y;
            tuple<char(&)[10], Y&>(a, y);

            It is possible to come up with a tuple type that cannot be constructed. This occurs if an element that cannot be initialized has a lower index than an element that requires initialization. For example: tuple<char[10], int&>.

            In sum, the tuple construction is semantically just a group of individual elementary constructions.

            The make_tuple function

            Tuples can also be constructed using the make_tuple (cf. std::make_pair) helper functions. This makes the construction more convenient, saving the programmer from explicitly specifying the element types:

            tuple<int, int, double> add_multiply_divide(int a, int b) {
            return make_tuple(a+b, a*b, double(a)/double(b));
            }

            By default, the element types are deduced to the plain non-reference types. E.g.:

            void foo(const A& a, B& b) { 
            ...
            make_tuple(a, b);

            The make_tuple invocation results in a tuple of type tuple<A, B>.

            Sometimes the plain non-reference type is not desired, e.g. if the element type cannot be copied. Therefore, the programmer can control the type deduction and state that a reference to const or reference to non-const type should be used as the element type instead. This is accomplished with two helper template functions: ref and cref. Any argument can be wrapped with these functions to get the desired type. The mechanism does not compromise const correctness since a const object wrapped with ref results in a tuple element with const reference type (see the fifth example below). For example:

            A a; B b; const A ca = a;
            make_tuple(cref(a), b); // creates tuple<const A&, B>
            make_tuple(ref(a), b); // creates tuple<A&, B>
            make_tuple(ref(a), cref(b)); // creates tuple<A&, const B&>
            make_tuple(cref(ca)); // creates tuple<const A&>
            make_tuple(ref(ca)); // creates tuple<const A&>

            Array arguments to make_tuple functions are deduced to reference to const types by default; there is no need to wrap them with cref. For example:

            make_tuple("Donald", "Daisy");

            This creates an object of type tuple<const char (&)[7], const char (&)[6]> (note that the type of a string literal is an array of const characters, not const char*). However, to get make_tuple to create a tuple with an element of a non-const array type one must use the ref wrapper.

            Function pointers are deduced to the plain non-reference type, that is, to plain function pointer. A tuple can also hold a reference to a function, but such a tuple cannot be constructed with make_tuple (a const qualified function type would result, which is illegal):

            void f(int i);
            ...
            make_tuple(&f); // tuple<void (*)(int)>
            ...

            volnet:
            boost::tuple<void (&)(int)> pFTuple3(f);

            pFTuple3.get<0>()(30);

            tuple<tuple<void (&)(int)> > a(f) // ok
            make_tuple(f); // not ok

            Accessing tuple elements

            Tuple elements are accessed with the expression:

            t.get<N>()

            or

            get<N>(t)

            where t is a tuple object and N is a constant integral expression specifying the index of the element to be accessed. Depending on whether t is const or not, get returns the Nth element as a reference to const or non-const type. The index of the first element is 0 and thus N must be between 0 and k-1, where k is the number of elements in the tuple. Violations of these constraints are detected at compile time. Examples:

            double d = 2.7; A a;
            tuple<int, double&, const A&> t(1, d, a);
            const tuple<int, double&, const A&> ct = t;
            ...
            int i = get<0>(t); i = t.get<0>(); // ok
            int j = get<0>(ct); // ok
            get<0>(t) = 5; // ok
            get<0>(ct) = 5; // error, can't assign to const
            ...
            double e = get<1>(t); // ok
            get<1>(t) = 3.14; // ok
            get<2>(t) = A(); // error, can't assign to const
            A aa = get<3>(t); // error: index out of bounds
            ...
            ++get<0>(t); // ok, can be used as any variable

            Note! The member get functions are not supported with MS Visual C++ compiler. Further, the compiler has trouble with finding the non-member get functions without an explicit namespace qualifier. Hence, all get calls should be qualified as: tuples::get<N>(a_tuple) when writing code that should compile with MSVC++ 6.0.

            Copy construction and tuple assignment

            A tuple can be copy constructed from another tuple, provided that the element types are element-wise copy constructible. Analogously, a tuple can be assigned to another tuple, provided that the element types are element-wise assignable. For example:

            class A {};
            class B : public A {};
            struct C { C(); C(const B&); };
            struct D { operator C() const; };
            tuple<char, B*, B, D> t;
            ...
            tuple<int, A*, C, C> a(t); // ok
            a = t; // ok

            In both cases, the conversions performed are: char -> int, B* -> A* (derived class pointer to base class pointer), B -> C (a user defined conversion) and D -> C (a user defined conversion).

            Note that assignment is also defined from std::pair types:

            tuple<float, int> a = std::make_pair(1, 'a');

            volnet:(Eclipse with MinGW g++
            conversion from `std::pair<int, char>' to non-scalar type `boost::tuples::tuple<float, int, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>' requested

            Relational operators

            Tuples reduce the operators ==, !=, <, >, <= and >= to the corresponding elementary operators. This means, that if any of these operators is defined between all elements of two tuples, then the same operator is defined between the tuples as well. The equality operators for two tuples a and b are defined as:

            • a == b iff for each i: ai == bi
            • a != b iff exists i: ai != bi

            The operators <, >, <= and >= implement a lexicographical ordering.

            Note that an attempt to compare two tuples of different lengths results in a compile time error. Also, the comparison operators are "short-circuited": elementary comparisons start from the first elements and are performed only until the result is clear.

            Examples:

            tuple<std::string, int, A> t1(std::string("same?"), 2, A());
            tuple<std::string, long, A> t2(std::string("same?"), 2, A());
            tuple<std::string, long, A> t3(std::string("different"), 3, A());

            bool operator==(A, A) { std::cout << "All the same to me..."; return true; }

            t1 == t2; // true
            t1 == t3; // false, does not print "All the..."

            Tiers

            Tiers are tuples, where all elements are of non-const reference types. They are constructed with a call to the tie function template (cf. make_tuple):

            int i; char c; double d; 
            ...
            tie(i, c, a);

            The above tie function creates a tuple of type tuple<int&, char&, double&>. The same result could be achieved with the call make_tuple(ref(i), ref(c), ref(a)).

            A tuple that contains non-const references as elements can be used to 'unpack' another tuple into variables. E.g.:

            int i; char c; double d; 
            tie(i, c, d) = make_tuple(1,'a', 5.5);
            std::cout << i << " " << c << " " << d;

            This code prints 1 a 5.5 to the standard output stream. A tuple unpacking operation like this is found for example in ML and Python. It is convenient when calling functions which return tuples.

            The tying mechanism works with std::pair templates as well:

            int i; char c;
            tie(i, c) = std::make_pair(1, 'a');
            Ignore

            There is also an object called ignore which allows you to ignore an element assigned by a tuple. The idea is that a function may return a tuple, only part of which you are interested in. For example (note, that ignore is under the tuples subnamespace):

            char c;
            tie(tuples::ignore, c) = std::make_pair(1, 'a');

            Streaming

            The global operator<< has been overloaded for std::ostream such that tuples are output by recursively calling operator<< for each element.

            Analogously, the global operator>> has been overloaded to extract tuples from std::istream by recursively calling operator>> for each element.

            The default delimiter between the elements is space, and the tuple is enclosed in parenthesis. For Example:

            tuple<float, int, std::string> a(1.0f,  2, std::string("Howdy folks!");

            cout << a;

            outputs the tuple as: (1.0 2 Howdy folks!)

            The library defines three manipulators for changing the default behavior:

            • set_open(char) defines the character that is output before the first element.
            • set_close(char) defines the character that is output after the last element.
            • set_delimiter(char) defines the delimiter character between elements.

            Note, that these manipulators are defined in the tuples subnamespace. For example:

            cout << tuples::set_open('[') << tuples::set_close(']') << tuples::set_delimiter(',') << a; 

            outputs the same tuple a as: [1.0,2,Howdy folks!]

            The same manipulators work with operator>> and istream as well. Suppose the cin stream contains the following data:

            (1 2 3) [4:5]

            The code:

            tuple<int, int, int> i;
            tuple<int, int> j;

            cin >> i;
            cin >> tuples::set_open('[') >> tuples::set_close(']') >> tuples::set_delimiter(':');
            cin >> j;

            reads the data into the tuples i and j.

            Note that extracting tuples with std::string or C-style string elements does not generally work, since the streamed tuple representation may not be unambiguously parseable.

            Performance

            All tuple access and construction functions are small inlined one-liners. Therefore, a decent compiler can eliminate any extra cost of using tuples compared to using hand-written tuple like classes. Particularly, with a decent compiler there is no performance difference between this code:

            class hand_made_tuple { 
            A a; B b; C c;
            public:
            hand_made_tuple(const A& aa, const B& bb, const C& cc)
            : a(aa), b(bb), c(cc) {};
            A& getA() { return a; };
            B& getB() { return b; };
            C& getC() { return c; };
            };

            hand_made_tuple hmt(A(), B(), C());
            hmt.getA(); hmt.getB(); hmt.getC();

            and this code:

            tuple<A, B, C> t(A(), B(), C());
            t.get<0>(); t.get<1>(); t.get<2>();

            Note, that there are widely used compilers (e.g. bcc 5.5.1) which fail to optimize this kind of tuple usage.

            Depending on the optimizing ability of the compiler, the tier mechanism may have a small performance penalty compared to using non-const reference parameters as a mechanism for returning multiple values from a function. For example, suppose that the following functions f1 and f2 have equivalent functionalities:

            void f1(int&, double&);
            tuple<int, double> f2();

            Then, the call #1 may be slightly faster than #2 in the code below:

            int i; double d;
            ...
            f1(i,d); // #1
            tie(i,d) = f2(); // #2

            volnet:
            int myX = -1;
            double myY = -2;
            boost::tuple<int, double> f2(2);
            boost::tie(myX, myY) = f2; // #2
            cout << "myX = " << myX << ", myY = " <<myY << endl;

            See [1, 2] for more in-depth discussions about efficiency.

            Effect on Compile Time

            Compiling tuples can be slow due to the excessive amount of template instantiations. Depending on the compiler and the tuple length, it may be more than 10 times slower to compile a tuple construct, compared to compiling an equivalent explicitly written class, such as the hand_made_tuple class above. However, as a realistic program is likely to contain a lot of code in addition to tuple definitions, the difference is probably unnoticeable. Compile time increases between 5 and 10 percent were measured for programs which used tuples very frequently. With the same test programs, memory consumption of compiling increased between 22% to 27%. See [1, 2] for details.

            Portability

            The library code is(?) standard C++ and thus the library works with a standard conforming compiler. Below is a list of compilers and known problems with each compiler:

            Compiler
            Problems

            gcc 2.95
            -

            edg 2.44
            -

            Borland 5.5
            Can't use function pointers or member pointers as tuple elements

            Metrowerks 6.2
            Can't use ref and cref wrappers

            MS Visual C++
            No reference elements (tie still works). Can't use ref and cref wrappers

            Acknowledgements

            Gary Powell has been an indispensable helping hand. In particular, stream manipulators for tuples were his idea. Doug Gregor came up with a working version for MSVC, David Abrahams found a way to get rid of most of the restrictions for compilers not supporting partial specialization. Thanks to Jeremy Siek, William Kempf and Jens Maurer for their help and suggestions. The comments by Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, David Abrahams and Hartmut Kaiser helped to improve the library. The idea for the tie mechanism came from an old usenet article by Ian McCulloch, where he proposed something similar for std::pairs.

            References

            [1] J?rvi J.: Tuples and multiple return values in C++, TUCS Technical Report No 249, 1999.

            [2] J?rvi J.: ML-Style Tuple Assignment in Standard C++ - Extending the Multiple Return Value Formalism, TUCS Technical Report No 267, 1999.

            [3] J?rvi J.:Tuple Types and Multiple Return Values, C/C++ Users Journal, August 2001.


            Last modified 2003-09-07

            ? Copyright Jaakko J?rvi 2001. Permission to copy, use, modify, sell and distribute this software and its documentation is granted provided this copyright notice appears in all copies. This software and its documentation is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.



             

            posted @ 2010-03-25 17:46 volnet 閱讀(1710) | 評(píng)論 (0)編輯 收藏

            貪心算法:輸入一組數(shù),由它組合出一個(gè)最大的可以被15整除

            命題:輸入一組數(shù),由它組合出一個(gè)最大的可以被15整除。
            思路:能被15整除的數(shù),必然能被5和3整除,則必須要滿足整除5和整除3的特征。

            用貪心法可以組合出這些數(shù)中最大的一個(gè)。(代碼如下)如果組合不出來(lái),則輸出impossible。否則輸出這個(gè)數(shù)。

            // Divide3.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
            //
            
            #include <cstdio>
            #include <iostream>
            #include <fstream>
            
            using namespace std;
            
            #define MAX 1000
            #define IMPOSSIBLE "impossible"
            
            char str[MAX];
            // 0的ASCII碼是48,9的ASCII碼是57,因此計(jì)數(shù)器數(shù)組的大小取為58,以利于快速取值
            int counter[58];
            
            // 附加檢驗(yàn)代碼,本程序中可不執(zhí)行
            bool checkInput(char *s);
            // 整理所有數(shù)字,并分別統(tǒng)計(jì)'0'-'9'各個(gè)數(shù)的計(jì)算結(jié)果
            void collect(char *s);
            // 判斷是否涵蓋'5'或者'0'
            // 證明:能被整除的數(shù)末尾必須是或者
            bool canDivideBy5or0();
            // 判斷一個(gè)字符是不是'3' '6' '9'中的一個(gè)
            inline bool belongsTo369(char c);
            // 貪心法將數(shù)字轉(zhuǎn)換成可以被整除的數(shù),并輸出結(jié)果
            bool connect();
            
            int main( )
            {
                freopen("input.txt", "r", stdin); //文件輸入輸出
                freopen("output.txt", "w", stdout);
            
                scanf("%s", str);
            
                // 為了加快速度略去字符串檢查,假設(shè)所有輸入都是合法的
                //if(!checkInput(str))
                //    printf("err");
            
                collect(str);
            
                // 輸出計(jì)數(shù)器
                //int i;
                //for(i='0'; i<='9'; ++i)
                //{
                //    printf("%c:%d\n", i,counter[i]);
                //}
            
                if(!canDivideBy5or0())//假如canDivideBy5or0()=false,即不能整除,則輸出impossible
                {
                    //printf("Can not be divided by 5 or 0!\n");
                    printf(IMPOSSIBLE);
                    return 0;
                }
                if(!connect())//假如connect()=false,即無(wú)法把字符數(shù)組連接起來(lái),則輸出impossible
                    printf(IMPOSSIBLE);
            
                //printf("%s", str);
            
                return 0;
            }
            
            void collect(char *s)//分別統(tǒng)計(jì)字符串中'0'-'9'的出現(xiàn)個(gè)數(shù)
            {
                int i = 0;  //i表示字符串的第i個(gè)字符
                while(s[i] != '\0' && i < MAX)
                {
                    ++counter[s[i]];
                    ++i;
                }
            }
            
            bool canDivideBy5or0()//如果字符串中出現(xiàn)過(guò)或,即能被整除,則輸出true,否則輸出false
            {
                if(counter['5'] > 0)
                    return true;
                if(counter['0'] > 0)
                    return true;
                return false;
            }
            
            bool belongsTo369(char c)//判斷一個(gè)字符是不是'3' '6' '9'中的一個(gè),如果是,則輸出true,否則輸出false
            {
                if(c == '3' || c == '6' || c == '9')
                    return true;
                return false;
            }
            
            bool connect()//把整個(gè)字符數(shù)組連接起來(lái),并輸出
            {
                bool canConnect = true;// canConnect是一個(gè)標(biāo)志,表示是否可以開始連接了?
            
                int i;
                int sum = 0;
            
                // 從最大的數(shù)開始遞減到,并將所有不是、、的數(shù)加起來(lái),將結(jié)果存放在sum中
                for(i='9'; i>'0'; --i)
                {
                    if(counter[i] == 0 || belongsTo369(i))//如果某個(gè)數(shù)字沒有的話,比如一個(gè)序列里沒有'9'就跳過(guò),或者如果有數(shù)字,但是它屬于,,,那也跳過(guò)。然后把剩下的數(shù)字都加起來(lái)   
                        continue;
                    sum += (counter[i] * (i - '0'));//(i - '0')因?yàn)槎际亲址?1','2',…所以,要-'0'得到它的數(shù)值,,…,然后乘以它的數(shù)量
            
                }
            
                int mod = sum % 3;
                if( mod == 0 )
                    canConnect = true;
                else if(mod == 1)
                {
                    canConnect = false;
                    for(i = '1'; i <= '9'; i+=3)
                    {
                        if(counter[i] != 0)
                        {
                            --counter[i];
                            canConnect = true;
                            break;
                        }
                        //else
                        //    canConnect = false;
                    }
                }
                else if(mod == 2)
                {
                    canConnect = false;
                    for(i = '2'; i <= '8'; i+=3)
                    {
                        if(counter[i] != 0)
                        {
                            --counter[i];
                            if(i=='5')
                            {        
                                if(counter['5']==0 && counter['0'] == 0)
                                {
                                    canConnect = false;
                                    break;
                                }
                            }
                            canConnect = true;
                            break;
                        }
                        //else 
                        //    canConnect = false;
                    }
                }
            
                if(!canConnect) //如果canConnect=false,返回false
                    return false;
            
                //以下為輸出。此時(shí)計(jì)數(shù)器里面的數(shù)值已經(jīng)是最終方案了,根據(jù)下面的規(guī)律,用貪心法生成輸出結(jié)果
                // 貪心法:
                // 要湊齊一個(gè)最大的整數(shù),那么它必須滿足兩個(gè)條件
                // 1、位數(shù)最多,比如和比?
                // 2、高位的數(shù)字盡量地大,比如和相比
                // 因此:應(yīng)該先滿足位數(shù)最多,因?yàn)榻Y(jié)果必然可以得到一個(gè)整除的數(shù)(定理)?
                // 則只需要滿足高位數(shù)字大即可,而既然是'9'到'0',因此依次從大到小輸出即可
                // 并且為了結(jié)果能乘除,所以最后一位必須為或者
                bool endWith5 = false;//endWith5是一個(gè)標(biāo)記,如果為true表示以結(jié)尾,如果為false表示以結(jié)尾
                int j = 0;
                int r = 0;
                if(counter['0'] == 0)//如果輸入的字符串中沒有,則必然要以結(jié)尾,這部分有錯(cuò),例如:輸出
                {
                    endWith5 = true;
                    --counter['5'];//減掉的目的是為了保留一個(gè),留在末尾才輸出
                }
                for(i = '9'; i >= '0'; --i)//計(jì)算器中的數(shù)字是'9'到'0',為了得到結(jié)果是最大的數(shù),依次從大到小輸出數(shù)字即可
                {
                    for(j = counter[i]; j > 0; --j)
                    {
                        //printf("%c", i);
                        str[r++] = i;
                    }
                }
                if(endWith5)//如果以結(jié)尾,則在末尾輸出一個(gè)
                    //printf("5");
                    str[r++] = '5';
                str[r] = '\0';
                printf("%s", str);
                return true;
            }
            
            
            
            
            
            /*
            關(guān)于整除的理論基礎(chǔ):http://www.cbe21.com/subject/maths/printer.phparticle_id=818
            
            “能被3整除的數(shù)的特征”教學(xué)實(shí)錄與評(píng)析
             
            金中
             
              
            一、復(fù)習(xí)舊知
            
             師:前面同學(xué)們學(xué)習(xí)了能被、整除的數(shù)的特征,下面老師就來(lái)檢查一下(板書出三個(gè)數(shù)字:、、),你能用、、這三個(gè)數(shù)字組成能被整除的三位數(shù)嗎?
            
             學(xué)生根據(jù)教師要求組數(shù),教師板書出學(xué)生組數(shù)的情況:、。
            
             師:為什么這樣組數(shù)?
            
             生:因?yàn)閭€(gè)位上是、、、、的數(shù)能被整除……
            
             師:同樣用這三個(gè)數(shù)字,你們能組成被整除的數(shù)嗎?
            
             教師根據(jù)學(xué)生組數(shù)的情況板書出:、。
            
            師:你們是怎樣想的?
            
             生:因?yàn)閭€(gè)位上是或的數(shù)都能被整除。
            
             [評(píng)]鋪墊復(fù)習(xí)不落俗套,采用組數(shù)的方法,既復(fù)習(xí)了能被、整除的數(shù)的特征,又激發(fā)了學(xué)生學(xué)習(xí)的興趣。
            
             二、講授新課
            
             (一)設(shè)置教學(xué)“陷阱”。
            
             師:如果仍用這三個(gè)數(shù)字,你能否組成能被整除的數(shù)呢?試一試。
            
             教師根據(jù)學(xué)生組數(shù)的情況板書出:、。
            
             師:這兩個(gè)數(shù)能被整除嗎?
            
             學(xué)生試除驗(yàn)證這兩個(gè)數(shù)能被整除。
            
             師:從這兩個(gè)能被整除的數(shù),你想到了什么?能被整除的數(shù)有什么特征?
            
             生:個(gè)位上是的倍數(shù)的數(shù)能被整除。(引導(dǎo)學(xué)生提出假設(shè)①)
            
             (二)制造認(rèn)知矛盾。
            
             師:剛才同學(xué)們是從個(gè)位上去尋找能被整除的數(shù)的“特征”的,那么個(gè)位上是的倍數(shù)的數(shù)就一定能被整除嗎?
            
             教師緊接著舉出、、等數(shù)讓學(xué)生試除判斷,由此引導(dǎo)學(xué)生推翻假設(shè)①。
            
             師:這幾個(gè)數(shù)個(gè)位上都是的倍數(shù),有的數(shù)能被整除,而有的數(shù)卻不能被整除。我們能從個(gè)位上找出能被3整除的數(shù)的特征嗎?
            
             生:不能。
            
             (三)設(shè)疑問(wèn)激興趣。
            
             師:請(qǐng)同學(xué)們?nèi)杂谩ⅰ⑦@三個(gè)數(shù)字,任意組成一個(gè)三位數(shù),看看它們能不能被整除。
            
             學(xué)生用、、這三個(gè)數(shù)字任意組成一個(gè)三位數(shù),通過(guò)試除發(fā)現(xiàn):所組成的三位數(shù)都能被整除。
            
             師:能被整除的數(shù)有沒有規(guī)律可循呢?下面我們一起來(lái)學(xué)習(xí)“能被整除的數(shù)的特征。”(板書課題)
            
             [評(píng)]教師通過(guò)設(shè)置教學(xué)“陷阱”,引導(dǎo)學(xué)生提出能被整除的數(shù)的特征的假設(shè),到推翻假設(shè),引發(fā)認(rèn)知矛盾,并再次創(chuàng)設(shè)學(xué)生探究的問(wèn)題情境,不僅有效地避免了“能被、整除的數(shù)的特征”思維定勢(shì)的影響,而且進(jìn)一步地激發(fā)了學(xué)生的求知欲望。
            
             (四)引導(dǎo)探究新知。
            
             師:觀察用、、任意組成的能被整除的三位數(shù),雖然它們的大小不相同,但它們有什么共同點(diǎn)?
            
             引導(dǎo)學(xué)生發(fā)現(xiàn):組成的三位數(shù)的三個(gè)數(shù)字相同,所不同的是這三個(gè)數(shù)字排列的順序不同。
            
             師:三個(gè)數(shù)字相同,那它們的什么也相同?
            
             生:它們的和也相同。
            
             師:和是多少?
            
             生:這三個(gè)數(shù)字的和是。
            
             師:這三個(gè)數(shù)字的和與有什么關(guān)系?
            
             生:是的倍數(shù)。
            
             師:也就是說(shuō)它們的和能被什么整除?
            
             生:它們的和能被整除。
            
             師:由此你想到了什么?
            
             學(xué)生提出假設(shè)②:一個(gè)數(shù)各位上的數(shù)的和能被整除,這個(gè)數(shù)就能被整除。
            
             師:通過(guò)同學(xué)們的觀察,有的同學(xué)提出了能被整除的數(shù)特征的假設(shè),但是同學(xué)們觀察的僅是幾個(gè)特殊的數(shù),是否能被整除的數(shù)都有這樣的特征呢?要說(shuō)明同學(xué)們的假設(shè)是正確的,我們需要怎么做?
            
             生:進(jìn)行驗(yàn)證。
            
             師:怎樣進(jìn)行驗(yàn)證呢?
            
             引導(dǎo)學(xué)生任意舉一些能被整除的數(shù),看看各位上的數(shù)的和能否被整除。(為了便于計(jì)算和研究,可讓學(xué)生任意舉出以內(nèi)的自然數(shù),然后乘以。)
            
             根據(jù)學(xué)生舉出的數(shù),教師完成如下的板書,并讓學(xué)生計(jì)算出各個(gè)數(shù)各位上的數(shù)的和進(jìn)行驗(yàn)證。
            
             附圖{圖} 
            
             師:通過(guò)上面的驗(yàn)證,說(shuō)明同學(xué)們提出的能被整除的數(shù)特征的假設(shè)怎樣?
            
             生:是正確的。
            
             師:請(qǐng)同學(xué)們翻開書,看看書上是怎樣概括出能被整除的數(shù)的特征的。引導(dǎo)學(xué)生閱讀教材第頁(yè)的有關(guān)內(nèi)容。
            
             師:什么叫各位?它與個(gè)位有什么不同?根據(jù)這個(gè)特征,怎樣判斷一個(gè)數(shù)能不能被整除?
            
             組織學(xué)生討論,加深能被整除的數(shù)的特征的認(rèn)識(shí),掌握判斷一個(gè)數(shù)能否被整除的方法。
            
             [評(píng)]在學(xué)生觀察的基礎(chǔ)上,引導(dǎo)他們提出能被整除的數(shù)特征的假設(shè),并驗(yàn)證假設(shè)是否正確,不僅充分調(diào)動(dòng)了學(xué)生學(xué)習(xí)的主動(dòng)性、積極性,而且滲透了從特殊到一般的數(shù)學(xué)思想方法,指導(dǎo)了學(xué)法。
            
             三、課堂練習(xí)
            
             (一)判斷下面各數(shù)能否被整除,并說(shuō)明理由。
            
             54 83 114 262 837 
            
             (二)數(shù)能被整除嗎?你是怎樣判斷的?有沒有更簡(jiǎn)捷的判斷方法?
            
             引導(dǎo)學(xué)生發(fā)現(xiàn):、、這三個(gè)數(shù)字本身就能被整除,因此它們的和自然能被整除。判斷時(shí)用不著把它們相加。
            
             (三)數(shù)能被整除嗎?(將中插入一些數(shù)字改編而成。)
            
             引導(dǎo)學(xué)生概括出迅速判斷一個(gè)數(shù)能否被整除的方法:()先去掉這個(gè)數(shù)各位上是、、的數(shù);()把余下數(shù)位上的數(shù)相加,并去掉相加過(guò)程中湊成、、的數(shù);()看剩下數(shù)位上的數(shù)能否被整除。
            
             (四)運(yùn)用上述判斷一個(gè)數(shù)能否被整除的方法,迅速判斷、、能否被整除。
            
             (五)在下面每個(gè)數(shù)的□里填上一個(gè)數(shù)字,使這個(gè)數(shù)有約數(shù)。它們各有幾種不同的填法?
            
             □4□□56□
            
             引導(dǎo)學(xué)生掌握科學(xué)的填數(shù)方法:()先看已知數(shù)位上的數(shù)字的和是多少;()如果已知數(shù)位上的數(shù)字和是的倍數(shù),那么未知數(shù)位的□里最小填“”,要填的其它數(shù)字可依次加上;如果已知數(shù)位上的數(shù)字和不是的倍數(shù),那么未知數(shù)位的里可先填一個(gè)最小的數(shù),使它能與已知數(shù)位上的數(shù)字和湊成是的倍數(shù),要填的其它數(shù)字可在此基礎(chǔ)上依次加上。
            
             (六)寫出兩個(gè)能被整除的多位數(shù)。
            
             [評(píng)]練習(xí)設(shè)計(jì)緊扣教學(xué)重點(diǎn),既注意遵循學(xué)生的認(rèn)識(shí)規(guī)律,循序漸進(jìn),又注重了學(xué)生的思維訓(xùn)練和科學(xué)解題方法的指導(dǎo),使學(xué)生數(shù)學(xué)能力的培養(yǎng)落到了實(shí)處。
            
             [總評(píng)]這節(jié)課教師采用“引導(dǎo)學(xué)習(xí)”的方法進(jìn)行教學(xué),有以下鮮明的特點(diǎn):.充分調(diào)動(dòng)了學(xué)生學(xué)習(xí)的積極性、主動(dòng)性,讓他們參與數(shù)學(xué)知識(shí)形成的全過(guò)程,從而確保了學(xué)生在學(xué)習(xí)中的主體地位。.教師在整個(gè)教學(xué)過(guò)程中立足于科學(xué)地引導(dǎo)學(xué)生的邏輯思維,輔導(dǎo)學(xué)生學(xué)會(huì)研究一類數(shù)學(xué)問(wèn)題的方法,指導(dǎo)學(xué)生掌握解題的技能技巧,體現(xiàn)出了教師善“導(dǎo)”、會(huì)“導(dǎo)”、科學(xué)地“導(dǎo)”、巧妙地“導(dǎo)”。.教師把數(shù)學(xué)知識(shí)的傳授、數(shù)學(xué)思想方法的滲透、學(xué)生學(xué)習(xí)方法的指導(dǎo)、學(xué)生的思維訓(xùn)練和數(shù)學(xué)能力的培養(yǎng)有機(jī)地結(jié)合起來(lái),收到優(yōu)質(zhì)、高效的教學(xué)效果。
            
            
            成師附小
            
            
             
            來(lái)自: 中基網(wǎng)>>教學(xué)參考
            www.cbe21.com    
            
            */

            posted @ 2010-03-25 17:37 volnet 閱讀(1030) | 評(píng)論 (0)編輯 收藏

            如何在Windows 7下安裝Wubi以啟動(dòng)安裝在Windows下(傳統(tǒng)方式+EasyBCD方式)

            如何在Windows 7下安裝Wubi以啟動(dòng)安裝在Windows下(傳統(tǒng)方式+EasyBCD方式)


            傳統(tǒng)方式

            1. 前提條件

              1. 本節(jié)適合“主分區(qū)+邏輯分區(qū)”的分區(qū)方式,不支持“系統(tǒng)分區(qū)+主分區(qū)+邏輯分區(qū)”的分區(qū)方式,也就是說(shuō),針對(duì)于Windows Vista之前的系統(tǒng),均適用本節(jié),針對(duì)Windows Vista以及之后的系統(tǒng),若是采用“系統(tǒng)分區(qū)+主分區(qū)+邏輯分區(qū)”的方式(如全盤重裝,包括劃分分區(qū)表(重要),安裝系統(tǒng)),本節(jié)可能并不適合,請(qǐng)參看下一節(jié)“EasyBCD方法。”
            2. 操作步驟

            3. 主要是Windows XP下,大家通過(guò)在boot.ini里增加“C:\wubildr.mbr="Ubuntu"”就可以啟動(dòng)Ubuntu。 而Windows 7則使用了BCD規(guī)則(也可以使用EasyBCD工具來(lái)運(yùn)行(相見下文))。

              下面的規(guī)則則較為簡(jiǎn)單:

              1. 打開XP下的ntldr,以及boot.ini,將其拷貝到Windows 7下(參考附件)
              2. 拷貝wubildr.mbr以及wubildr至主分區(qū)(C盤)(這個(gè)即便在XP下你也需要完成)
              3. 重新啟動(dòng)系統(tǒng)即可。

              下載文件:ntldr.zip (32bit)

            EasyBCD方法

            1. 前提條件

              1. 你的Ubuntu是通過(guò)wubi的方式安裝的,Grub的方式也類似,只不過(guò)是設(shè)置的時(shí)候選擇別的選項(xiàng),這里不做描述。
              2. 本節(jié)基本適合于Windows(Vista/7)(x86/x64),(XP以及之前的系統(tǒng)適合下面步驟2)對(duì)于步驟2中提及的方法可以實(shí)現(xiàn)的建議按舊方案。
              3. 本節(jié)不適合即將在當(dāng)前Windows環(huán)境下全新安裝Ubuntu的用戶。
              4. Windows系統(tǒng)是System分區(qū)+主分區(qū)+邏輯分區(qū) 構(gòu)成的。(例如:不是從XP或者其它系統(tǒng)升級(jí)而成的,而是全新安裝的)

            2. 操作步驟

              1. 我在舊系統(tǒng)(WinXP)下安裝Ubuntu(by wubi)。
              2. 我將Ubuntu放在我的移動(dòng)硬盤里面,并與我的另一臺(tái)電腦共享(Win7 x86),共享方法:http://forum.ubuntu.org.cn/viewtopic.php?f=48&t=248205
              3. 我購(gòu)置了新電腦,并安裝了Win7 x64,但步驟2中所提及的適用于Win7 x86的共享方法失效了。(不知是否需要將ntldr替換為x64版的方可生效?因?yàn)槲覜]有,所以不確定)
              4. 我下載了EasyBCD,選擇了“Add/Remove Entries”,選擇了“Linux”選項(xiàng)卡,并選擇Type為“wubi”,于是它在我的C:\下放置了\Device\HarddiskVolume1文件夾以及其中的內(nèi)容,想必就是一個(gè)wubildr.mbr吧?查看menu.lst,主要內(nèi)容如下:
              5. find --set-root --ignore-floppies \ubuntu\winboot\menu.lst
                configfile \ubuntu\winboot\menu.lst
              6. 通過(guò)EasyBCD的“ViewSettings”,看到:
              7. Entry #2

                Name: NeoSmart Linux
                BCD ID: {46ca74c9-fdd2-11de-914a-a89213a2f2bd}
                Drive: \Device\HarddiskVolume1
                Bootloader Path: \NST\NeoGrub.mbr
              8. 因?yàn)椴襟E5中的Drive不是盤符(對(duì)應(yīng)Windows7的項(xiàng),你很容易分辨出來(lái)),因此在“Change Settings”中的“Entity-Based Setting”,選擇你剛設(shè)置的Ubuntu,并選擇Drive為C盤(對(duì)應(yīng)步驟2中所提及的共享方法)
              9. 在步驟2中所提及的共享方法里含有兩個(gè)文件wubildr.mbr以及wubildr。我們?cè)赪in7x64所遭遇的問(wèn)題就是無(wú)法通過(guò)啟動(dòng)項(xiàng)目的設(shè)置,讓系統(tǒng)啟動(dòng)的時(shí)候找到這個(gè)wubildr.mbr文件,但在EasyBCD中看來(lái),也似乎沒有地方可以改變NeoGrub.mbr的名字,那么一個(gè)折中的方案就是將wubildr.mbr的名字修改成NeoGrub.mbr,并將其放在C盤(在之前步驟的Drive中設(shè)置)下的NST目錄中,并將舊的wubildr文件拷貝至C盤(同樣等同于Drive的盤符設(shè)置)
              10. 至此,重新啟動(dòng)電腦,應(yīng)該就會(huì)出現(xiàn)你所熟悉的場(chǎng)景了。

            posted @ 2010-01-16 20:16 volnet 閱讀(2548) | 評(píng)論 (0)編輯 收藏

            C語(yǔ)言位域

            這個(gè)概念顯然是知道的,不過(guò)剛才忘了,然后寫了個(gè)程序就明白了,記錄一下,也許以后又健忘了:
             1 #include <stdio.h>
             2 typedef struct _SimpleType1 {
             3     int Variable1;    //4bytes(32bits)
             4     int Variable2;    //4bytes(32bits)
             5     int Variable3;    //4bytes(32bits)
             6     int Variable4;    //4bytes(32bits)
             7 } SimpleType1;
             8 
             9 typedef struct _ComplexType1 {
            10     int Variable1 : 8;    //1bytes(8bits)
            11     int Variable2 : 8;    //1bytes(8bits)
            12     int Variable3 : 8;    //1bytes(8bits)
            13     int Variable4 : 8;    //1bytes(8bits)
            14 } ComplexType1;
            15 
            16 typedef struct _ComplexType2 {
            17     int Variable1 : 8;    //1bytes(8bits)
            18     int Variable2 : 8;    //1bytes(8bits)
            19     int Variable3 : 8;    //1bytes(8bits)
            20     int Variable4 : 8;    //1bytes(8bits)
            21     int Variable5 : 1;    //0.125bytes(1bits) but the it also hold 32bits 
            22 } ComplexType2;
            23 
            24 int main(void){
            25     printf("sizeof SimpleType1 = %d\n"sizeof(SimpleType1));
            26     printf("sizeof ComplexType1 = %d\n"sizeof(ComplexType1));
            27     printf("sizeof ComplexType2 = %d\n"sizeof(ComplexType2));
            28 }
            結(jié)果:
            sizeof SimpleType1 = 16
            sizeof ComplexType1 = 4
            sizeof ComplexType2 = 8

            posted @ 2009-12-30 01:02 volnet 閱讀(802) | 評(píng)論 (0)編輯 收藏

            關(guān)于線程同步的一些總結(jié)(用戶模式/內(nèi)核模式)

            自旋鎖同步

            1. 一般是為了內(nèi)核態(tài)下各個(gè)派遣函數(shù)之間做同步作用的。
            2. 原理是(單CPU)將IRQL從軟件中斷提升到硬件中斷。PASSIVE_LEVEL->DISPATCH_LEVEL。因?yàn)樵贒ISPATCH_LEVEL中是不會(huì)出現(xiàn)線程切換的(只有高級(jí)別能打斷低級(jí)別,而低級(jí)別不能打斷高級(jí)別)。
            3. 因?yàn)榉猪?yè)內(nèi)存將導(dǎo)致如果線程切換的時(shí)候會(huì)引起分頁(yè)數(shù)據(jù)交換,數(shù)據(jù)交換是通過(guò)引發(fā)頁(yè)故障來(lái)實(shí)現(xiàn)的,而頁(yè)故障是不允許出現(xiàn)在DISPATCH_LEVEL中的,否則將引起系統(tǒng)崩潰(PASSIVE_LEVEL則允許)。驅(qū)動(dòng)程序的StartIO例程、DPC例程、中斷服務(wù)例程都運(yùn)行在DISPATCH_LEVEL或者更高的IRQL。因此這些例程不能使用分頁(yè)內(nèi)存,否則將導(dǎo)致系統(tǒng)崩潰。
            4. 自旋鎖在不同IRP之間同步的時(shí)候,則需要放在DeviceExtension中傳遞。

            互鎖

            1. 類似于number++; //匯編后將不止一條語(yǔ)句,非原子操作number--; //同上因?yàn)檎Z(yǔ)句會(huì)變成多句,在線程切換的時(shí)候,兩個(gè)線程下的該例程將會(huì)交織在一起執(zhí)行,導(dǎo)致錯(cuò)誤。可以:
              先加鎖
              number++;
              解鎖
              再加鎖
              number--;
              解鎖
              來(lái)實(shí)現(xiàn)兩句話的同步(按指定順序執(zhí)行,而不受到線程切換的影響)加鎖解鎖可以使用自旋鎖
            2. 在系統(tǒng)中提供了Interlocked***/ExInterlocked***實(shí)現(xiàn)

            信號(hào)燈同步

            1. 線程1關(guān)閉信號(hào)燈,以至于使用Wait****的時(shí)候,當(dāng)前線程處于暫停狀態(tài)。
            2. 線程2的作用就是在執(zhí)行結(jié)束后,點(diǎn)亮信號(hào)燈(增加計(jì)數(shù)器)。當(dāng)線程切換回來(lái)的時(shí)候,線程1就因?yàn)橛?jì)數(shù)器不是0而使信號(hào)燈處于激活狀態(tài),從而繼續(xù)執(zhí)行線程1。

            事件的同步

            (不能遞歸獲取互斥體)
            1. 主線程在輔助線程上設(shè)置了事件,如果不使用Wait**等待事件返回,則主線程可能直接執(zhí)行完畢了,而導(dǎo)致輔助線程還在執(zhí)行。
            2. 使用Wait****可以使主線程等待事件執(zhí)行完成。

            互斥體同步

            (允許遞歸獲取互斥體(得到互斥體的線程還可以再次獲得這個(gè)互斥體,或者說(shuō)互斥體對(duì)于已經(jīng)獲得互斥體的線程不產(chǎn)生“互斥”關(guān)系))
            1. 創(chuàng)建一個(gè)互斥體對(duì)象,將互斥體對(duì)象傳遞給多個(gè)線程。
            2. 在每個(gè)線程操作的步驟中,調(diào)用Wait*****,如果互斥體處于激活(內(nèi)部維護(hù)一個(gè)計(jì)數(shù)器),則繼續(xù)執(zhí)行后續(xù)代碼,并在調(diào)用結(jié)束后恢復(fù)互斥體Release****,這樣當(dāng)別的線程試圖使用互斥體后面的代碼的時(shí)候,因?yàn)榛コ怏w狀態(tài)未激活,則無(wú)法繼續(xù)執(zhí)行代碼。

            快速互斥體同步

            1. 與互斥體同步類似,唯一區(qū)別是不允許遞歸獲取互斥體

            posted @ 2009-12-26 05:53 volnet 閱讀(2094) | 評(píng)論 (2)編輯 收藏

            如何編譯TrueCrypt源碼

            相關(guān)配置

                 
            • Intel x86 Core 2 Duo
            •    
            • Windows 7 Ultimate x86 version
            •    
            • Windows Driver Develop Kit 7600.16385.0
            •    
            • TrueCrypt 6.3a Source.zip
            •    
            • Microsoft Visual Studio 2008 SP1 (VC++ 2008)
            •    
            • Microsoft Visual Studio VC++ 1.52
            •    
            • NASM version 2.07 compiled on Jul 19 2009
            •    
            • gzip 1.2.4 Win32 (02 Dec 97)
            •    
            • ......

            配置TrueCrypt

            1. 下載MSVC++ 1.52,安裝在C盤下:C:\MSVC
            2. 下載NASM,也安裝在C盤下:C:\NASM
              http://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/
            3. 下載GZIP,也安裝在C盤下:C:\gzip
            4. 下載并安裝WINDDK,http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx
              我將它們安裝在D盤,路徑:D:\WinDDK
            5. 設(shè)置系統(tǒng)變量((WIN7)控制面板\所有控制面板項(xiàng)\系統(tǒng)\高級(jí)系統(tǒng)設(shè)置\環(huán)境變量):系統(tǒng)變量中,新增:
              變量1:MSVC16_ROOT    值:C:\MSVC
              變量2:WINDDK_ROOT    值:D:\WinDDK\7600.16385.0
              其中7600.16385.0為WinDDK的第二級(jí)目錄名,同時(shí)也是版本號(hào),7600是Windows7的發(fā)行版本號(hào)。
              雙擊變量:PATH,在其值的末尾補(bǔ)上:C:\NASM;C:\gzip
              目的是為了讓我們可以直接在命令行實(shí)用nasm以及gzip作為命令行。
            6. 下載PKCS11,三個(gè)文件,右鍵另存為即可。
              http://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/
              將三個(gè)文件(pkcs11.h、pkcs11f.h、pkcs11t.h)拷貝到源碼下的Common文件夾下,我的源碼放在D盤根目錄,三個(gè)源碼我就放在“D:\TrueCrypt\Common”文件夾中。
            7. 編譯,會(huì)發(fā)現(xiàn)有兩個(gè)錯(cuò)誤。
              CKR_NEW_PIN_MODE和CKR_NEXT_OTP未定義,補(bǔ)充定義一下即可。
              在d:\TrueCrypt\Common\pkcs11t.h文件里(請(qǐng)根據(jù)您自己的路徑進(jìn)行復(fù)制)
              這里將它們?cè)O(shè)置為:
              #define CKR_NEW_PIN_MODE      0x000001B0
              #define CKR_NEXT_OTP          0x000001B1
              我的方法是找到實(shí)用它的語(yǔ)句附近的同類語(yǔ)句,找到相同的定義,在其下方添加。
              比如:
                          TC_TOKEN_ERR (CKR_MUTEX_NOT_LOCKED)
                          TC_TOKEN_ERR (CKR_NEW_PIN_MODE)
                          TC_TOKEN_ERR (CKR_NEXT_OTP)
              這三句話放在一起,后兩句有問(wèn)題,但第一句正常,則查找CKR_MUTEX_NOT_LOCKED的存放位置,在其下方添加如上兩句,其中定義的值參考
              http://www.cryptsoft.com/pkcs11doc/STANDARD/include/v220/otp-pkcs11.h,這里的值只不過(guò)是一種錯(cuò)誤碼,只要它不重復(fù),就可以了。
            8. 再編譯,可能會(huì)遇到一些警告:
              1. nasm.exe正在停止,而因?yàn)闆]有正確執(zhí)行,又導(dǎo)致“fatal error LNK1136: invalid or corrupt file”錯(cuò)誤。
                遇到這個(gè)可能是因?yàn)槟愕膎asm正在試圖編譯ase_amdX64.asm文件,而nasm對(duì)64位的asm編譯對(duì)你可能意義不大,起碼對(duì)我而言是這樣的,于是,我就將它轉(zhuǎn)成編譯x86體系架構(gòu)的,也許是因?yàn)閰?shù)配置的問(wèn)題,你可以嘗試別的方案,如果有更好的話,請(qǐng)告訴我。
                這里我搜索:x64、asm等關(guān)鍵字,修改d:\TrueCrypt\Crypto\Makefile.inc文件為下面這樣即可:
                行1    !if "$(TC_ARCH)" == "x86"
                行2    TC_OBJ_FORMAT = win32
                行3    !else
                行4    #TC_OBJ_FORMAT = win64
                行5    #edit by gocool, if the x64 system need the nasm.exe use the x64 format parameters for executing.
                行6    #abort the x64 system here for building.
                行7    #2009/12/23
                行8    TC_OBJ_FORMAT = win32
                行9    TC_ARCH = x86
                行10    !endif
                行11   
                行12    "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj": Aes_$(TC_ARCH).asm
                行13        nasm.exe -Xvc -f $(TC_OBJ_FORMAT) -Ox -D DLL_EXPORT -o "$@" -l "$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).lst" Aes_$(TC_ARCH).asm
                其中,為了減少變化量,也利于以后恢復(fù),第4-7行為注釋,第8、9行我將非x86的情況也定義成x86的情況,這樣無(wú)論如何下面第13行的語(yǔ)句都將執(zhí)行以x86體系為結(jié)構(gòu)的設(shè)置,而這樣的設(shè)置通常是正確的。
              2. fatal error LNK1000: Internal error during IncrBuildImage
                據(jù)說(shuō)是Microsoft Visual Studio 2008的一個(gè)BUG。http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx
                聽說(shuō)有兩種方法,一種是方法1,需要下載補(bǔ)丁,我沒有嘗試。第二種通過(guò)修改配置的方法我成功了,步驟如下:
                方法:項(xiàng)目->屬性->鏈接器->常規(guī)   下面的“啟用增量鏈接”,將“是(/INCREMENTAL)”改為“否(/INCREMENTAL:NO)”。
                不過(guò)這又引入了另外一個(gè)警告:3>FormatCom.obj : warning LNK4075: 忽略“/EDITANDCONTINUE”(由于“/INCREMENTAL:NO”規(guī)范)
                選擇項(xiàng)目,屬性->配置屬性->C/C++,修改“調(diào)試信息格式”為“程序數(shù)據(jù)庫(kù)(/Zi)”即可。
              3. 警告:未找到下列環(huán)境變量
                4>項(xiàng)目 : warning PRJ0018 : 未找到下列環(huán)境變量:
                4>$(PKCS11_INC)
                由于項(xiàng)目屬性里設(shè)置有附加包含目錄“$(PKCS11_INC)”,因此編譯的時(shí)候會(huì)在系統(tǒng)變量里尋找PKCS11_INC項(xiàng)目,如果找不到,則給出警告,因此,我們需要手動(dòng)補(bǔ)充這個(gè)項(xiàng)。方法同步驟5,增加一個(gè)變量為PKCS11_INC,值:D:\TrueCrypt\Common,其中,值就是之前我們拷貝三個(gè)文件(pkcs11.h、pkcs11f.h、pkcs11t.h)的目錄。
              4. 如果不出意外的話,你可能還會(huì)得到一個(gè)使用了PKEY_AppUserModel_ID未定義的聲明符的錯(cuò)誤。這個(gè)是用于標(biāo)識(shí)用戶態(tài)應(yīng)用程序的唯一標(biāo)識(shí)。你可以在Setup.h文件中定義:
                /*---region add by gc---*/
                #include "wtypes.h"
                    const PROPERTYKEY PKEY_AppUserModel_ID = {
                        {
                            (unsigned long)2009,/*unsigned long  Data1;*/
                            (unsigned short)12,/*unsigned short Data2;*/
                            (unsigned short)23,/*unsigned short Data3;*/
                            0x44,0x55,0x55,0x55,0x55,0x55,0x55,0x55
                        },/*GUID fmtid;*/
                        (DWORD)PID_FIRST_USABLE /*DWORD pid;*/
                    };
                /*---endregion---*/
                其中,這個(gè)結(jié)構(gòu)體是由GUID和PID共同組成的。

            下載鏈接

          1. TrueCrypt下載:http://www.sfr-fresh.com/windows/misc/TrueCrypt-6.2a-Source.zip:a/Boot/Windows/Makefile
          2. WinDDK下載:http://www.microsoft.com/whdc/DevTools/WDK/WDKpkg.mspx
          3. PKCS11下載:http://svn.openvpn.net/projects/openvpn/test/time/openvpn/pkcs11-headers/
          4. GZip下載:http://www.gzip.org/ 或者 http://www.gzip.org/gz124src.zip
          5. Nasm下載:http://www.nasm.us/pub/nasm/releasebuilds/2.07/win32/
          6. MSVC1.52下載:http://download.csdn.net/source/620960 (15.02MB)(似乎網(wǎng)上很多人都在找1.52(最后一個(gè)可以編譯16bit程序的VC編譯器),但官方網(wǎng)站上沒有公開下載的鏈接,實(shí)在非常郁悶,我從MSDN訂閱下載(收費(fèi)的噢,杯具)則有67.6MB),如果大家實(shí)在找不到下載或者15.02MB的不可用,可以聯(lián)系我。

          7. 參考鏈接

            • http://blog.csdn.net/skyremember/archive/2009/09/17/4562090.aspx
            • http://blog.sina.com.cn/s/blog_4758691d0100d8mc.html
            • http://lll332.blog.163.com/blog/static/1553692220093404635752/
            • http://msdn.microsoft.com/en-us/library/aa373931%28VS.85%29.aspx
            • http://hi.baidu.com/hhacker/blog/item/2fc5b3fb0b24132a4f4aea1d.html
            • http://blog.csdn.net/just_one_two/archive/2009/10/05/4634391.aspx
            • http://blog.csdn.net/liufei_learning/archive/2009/12/21/5047632.aspx
            • http://msdn.microsoft.com/zh-cn/library/958x11bc%28VS.80%29.aspx
            • http://bbs.xiakexing.com/cgi-bin/topic.cgi?forum=22&topic=498

            posted @ 2009-12-23 23:47 volnet 閱讀(5923) | 評(píng)論 (10)編輯 收藏

            我的Linux小記(1)

            1、如何啟動(dòng)命令行?
            答:GNOME環(huán)境下,按Alt+F2,在隨后出現(xiàn)的運(yùn)行窗口中輸入:gnome-terminal,回車。如圖所示:

            2、如何以管理員權(quán)限運(yùn)行命令?
            答:Ubuntu下:
            方法1:在命令行下,輸入su,在提示下輸入密碼(不會(huì)明文顯示),回車,接下來(lái)的命令都將以管理員權(quán)限運(yùn)行。
            方法2:在命令行下,需要用到管理員權(quán)限運(yùn)行的語(yǔ)句前加sudo(僅對(duì)單條語(yǔ)句有效),如果是當(dāng)前命令行窗口下第一次用此命令,則需要輸入密碼,按提示輸入密碼,回車,之后只需要用sudo,將不再輸入密碼。
            3、如何在Ubuntu下禁用觸摸板?
            答:在命令行中(參考1、2),輸入以下命令,禁用觸摸板:
            sudo rmmod psmouse

             

            重新啟用,則在命令行下(Alt+F2啟動(dòng)后輸入gnome-terminal),輸入以下命令,啟用觸摸板:
            sudo modprobe psmouse
            如圖所示:

            4、如何用head和tail命令?
            head命令用于顯示文件的前10行,而tail命令則用于顯示文件的后10行。
            支持的參數(shù)有:
            -c N:顯示前(后)N字節(jié)的內(nèi)容
            -n N:顯示前(后)N行的內(nèi)容
            5、如何用shell為文件重命名呢?
            在Linux中似乎沒有rename這樣一個(gè)方法,但是可以通過(guò)mv(移動(dòng)文件)來(lái)為文件重命名:
            mv ./file-name1 ./file-name2
            通過(guò)在同級(jí)目錄下移動(dòng)文件,并指定文件名即可為文件重命名。

            6、fortune命令
            聽說(shuō)是個(gè)傳奇的命令,聽名字就是吧?那就試試,結(jié)果Ubuntu并沒有自帶,那么輸入下面語(yǔ)句安裝fortune。

            sudo apt-get install fortune-mod

            posted @ 2009-12-13 19:01 volnet 閱讀(671) | 評(píng)論 (0)編輯 收藏

            QuickSort快速排序法(2009-10-28)

            在本博客,之前有一個(gè)版本的QuickSort,其實(shí)網(wǎng)友很早就提出了相關(guān)的BUG,但是我一直沒有時(shí)間進(jìn)行修正,今天又有朋友提出了這個(gè)BUG,我剛好抽空看了一下,看來(lái)自己是相當(dāng)不嚴(yán)謹(jǐn)以至于犯下了如此大錯(cuò)。

            原文鏈接:http://m.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.aspx (未修復(fù))

            關(guān)于修復(fù)BUG后的代碼,將在本文中提供,原文中不進(jìn)行修改,但會(huì)有提示指明是錯(cuò)誤的,有興趣的朋友也可以直接在原文的代碼中尋找錯(cuò)誤來(lái)鍛煉自己排錯(cuò)的能力。

            下面就是幾段代碼:

            Algorithms.cpp

            #include "StdAfx.h"
            #include "Algorithms.h"
            Algorithms::Algorithms(void)
            {
            }
            
            Algorithms::~Algorithms(void)
            {
            }
            

            Algorithms.h

            #pragma once
            
            #include <iostream>
            
            class Algorithms
            {
            public:
                Algorithms(void);
                ~Algorithms(void);
            
            public:
                template <typename T>
                static void QuickSort(T* arr, size_t min, size_t max);
            private:
                template <typename T>
                static size_t qsort_helper_partition(T* arr, size_t min, size_t max);
                template <typename T>
                static inline void swap(T* arr, size_t x, size_t y);
                // helper
                template <typename T>
                static inline void helper_show_all(T* arr, size_t min, size_t max, char *msg);
            };
            
            template <typename T>
            void Algorithms::QuickSort(T* arr, size_t min, size_t max)
            {
                if(min >= max || max == 0 - 1) return;
                helper_show_all(arr, min, max, "before qsort_helper_partition");
                size_t p = qsort_helper_partition(arr, min, max);
                helper_show_all(arr, min, max, "after qsort_helper_partition");
            
                QuickSort(arr, min, p - 1);
                QuickSort(arr, p + 1, max);
            }
            /*
            *    @BUG:    bug200910280001
            *    @DESC:    由于在循環(huán)while(true)中,假設(shè)原代碼
                        01    while(true)
                        02    {
                        03        while(cmp < arr[i])
                        04            ++i;
                        05        while(arr[j] < cmp)
                        06            --j;
                        07        if(i >= j) break;
                        08
                        09        swap(arr, i, j);
                        10    }
                        中,前兩段(行號(hào),行號(hào))中的代碼均返回false,
                        則無(wú)法進(jìn)入++i或者--j,那么在這個(gè)while(true)中,
                        i和j的值將無(wú)法發(fā)生變化,從而導(dǎo)致死循環(huán)。
                @LINK:http://m.shnenglu.com/mymsdn/archive/2009/03/06/quicksort.aspx#99606
            */
            template <typename T>
            size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
            {
                T cmp = arr[min];
                int i = min, j = max; // bug200910280001:修正i = min+1,將+1的動(dòng)作放在循環(huán)內(nèi)。
                while(true)
                {
                    while(cmp < arr[++i]) // bug200910280001:將原本在循環(huán)外的min+1,移進(jìn)循環(huán)內(nèi),并首先+1
                        ; // bug200910280001:將++1移至while條件中。
                    while(arr[j] < cmp)
                        --j;
                    if(i >= j) break;
            
                    helper_show_all(arr, min, max, "before swap(arr, i, j)");
                    swap(arr, i, j);
                    helper_show_all(arr, min, max, "after swap(arr, i, j)");
                }
                swap(arr, min, j);
                return j;
            }
            
            template <typename T>
            void Algorithms::swap(T* arr, size_t x, size_t y)
            {
                T tmp = arr[x];
                arr[x] = arr[y];
                arr[y] = tmp;
            }
            
            template <typename T>
            void Algorithms::helper_show_all(T* arr, size_t min, size_t max, char *msg)
            {
                std::cout << "current array :\t";
                for(int i = min; i < max; ++i)
                {
                    std::cout << arr[i] << " ";
                }
                std::cout<<"\t//"<<msg;
                std::cout<<std::endl;
            }

            cpp_quickSort.cpp

            // cpp_quickSort.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
            //
            
            #include "stdafx.h"
            #include "Algorithms.h"
            #include <iostream>
            #include <vector>
            #include <algorithm>
            
            int _tmain(int argc, _TCHAR* argv[])
            {
                int arr_begin = 0;
                int arr_length = 12; //The length will instead of the magic numbers 
                int arr[] = {8, 3, 7, 1, 5, 6, 2, 1, 9, 9, 1, 1};
                
                // Test for : 20091028bug0001
                // int arr[] = {1, 1, 1};
            
                std::cout << "input array :\t";
                for(size_t i = arr_begin; i != arr_length; ++i)
                {
                    std::cout<<arr[i]<<" ";
                }
                std::cout<<std::endl;
            
                Algorithms::QuickSort(arr, arr_begin, arr_length);
            
                std::cout << "result array :\t";
                for(size_t i = arr_begin; i != arr_length; ++i)
                {
                    std::cout<<arr[i]<<" ";
                }
                std::cout<<std::endl;
            
                std::cout << "--------------------" << std::endl;
                std::cout << "input array :\t";
            
                std::vector<int> vec;
                vec.push_back(3);
                vec.push_back(1);
                vec.push_back(4);
                vec.push_back(1);
                vec.push_back(7);
                vec.push_back(6);
            
                for(std::vector<int>::iterator iter = vec.begin();
                    iter != vec.end(); ++ iter)
                {
                    std::cout<<*iter<<" ";
                }
                std::cout<<std::endl;
            
                std::sort(vec.begin(), vec.end());
            
                for(std::vector<int>::iterator iter = vec.begin();
                    iter != vec.end(); ++ iter)
                {
                    std::cout<<*iter<<" ";
                }
                std::cout<<std::endl;
            
                return 0;
            }
            
            

            posted @ 2009-10-28 00:38 volnet 閱讀(1237) | 評(píng)論 (0)編輯 收藏

            僅列出標(biāo)題
            共9頁(yè): 1 2 3 4 5 6 7 8 9 
            特殊功能
             
            国产精品一区二区久久不卡| 久久久久99精品成人片| 久久影视综合亚洲| 久久精品嫩草影院| 9久久9久久精品| 国产一级做a爰片久久毛片| 色欲久久久天天天综合网| 欧美亚洲国产精品久久高清| 国产一区二区久久久| 国产偷久久久精品专区| 国内精品久久久久影院薰衣草 | 成人a毛片久久免费播放| 国产精品久久久久AV福利动漫| 亚洲熟妇无码另类久久久| 久久久久人妻精品一区二区三区| 亚洲国产精品无码久久久不卡| 久久亚洲私人国产精品| 国产人久久人人人人爽| 日本精品久久久中文字幕| 久久精品成人免费国产片小草 | 久久精品成人免费看| 色综合久久88色综合天天| 一级做a爱片久久毛片| 久久久久无码精品| 77777亚洲午夜久久多人| 久久精品中文字幕无码绿巨人| 99久久99久久精品免费看蜜桃| 国内精品久久久久久麻豆| 香蕉久久夜色精品国产2020| 亚洲国产精品无码久久一线| 久久久久久a亚洲欧洲aⅴ| 久久精品无码一区二区三区| 久久亚洲av无码精品浪潮| 亚洲中文字幕无码久久2017| 伊人丁香狠狠色综合久久| 一级A毛片免费观看久久精品| 久久午夜羞羞影院免费观看| 99久久夜色精品国产网站| 久久人妻无码中文字幕| 国产农村妇女毛片精品久久| 久久精品国产AV一区二区三区|