home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Journal 1990 - 1995 / CUJ.iso / unix / 1995.txt < prev   
Text File  |  1996-02-07  |  3MB  |  77,685 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.  
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338.  
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.  
  397.  
  398.  
  399.  
  400.  
  401.  
  402.  
  403.  
  404.  
  405.  
  406.  
  407.  
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415.  
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449.  
  450.  
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458.  
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466.  
  467.  
  468.  
  469.  
  470.  
  471.  
  472.  
  473.  
  474.  
  475.  
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487.  
  488.  
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510.  
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535.  
  536.  
  537.  
  538.  
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581.  
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608.  
  609.  
  610.  
  611.  
  612.  
  613. Portable Byte Ordering in C++
  614.  
  615.  
  616. Philip J. Erdelsky
  617.  
  618.  
  619. Philip J. Erdelsky, Ph.D., is an R&D Engineer for Data/Ware Development, Inc.,
  620. in San Diego, California. He has been writing software in C and C++ for more
  621. than ten years. He can be reached at 75746.3411@compuserve.com.
  622.  
  623.  
  624.  
  625.  
  626. Which End is Up?
  627.  
  628.  
  629. I once facetiously asked a computer scientist where he stood on one of the
  630. greatest issues facing computing science. He must have sensed my mood, because
  631. he answered "squarely on the fence" before I could tell him what the issue
  632. was.
  633. The issue, of course, was byte order. Some CPUs, such as the Intel 80X86
  634. family, store multi-byte words in little-endian order, with the least
  635. significant byte (the little end) at the lowest address. Others, such as the
  636. Motorola 680X0 family, store them in big-endian order, with the most
  637. significant byte (the big end) at the lowest address. The terms "big endian"
  638. and "little endian" are supported by a literary allusion to Jonathan Swift's
  639. classic novel Gulliver's Travels, in which two nations fought a war to
  640. determine whether soft-boiled eggs should be opened at the big end or the
  641. little end.
  642. Each byte order has its own small advantage. Due to historical accident,
  643. numbers are written in big-endian order in English and other major western
  644. languages. That makes a memory dump easier to read if big-endian order is
  645. used. Addition, subtraction, and multiplication are done in little-endian
  646. order, so a little-endian CPU sometimes has a slight speed advantage when
  647. performing these operations in multiple precision.
  648. Could the world standardize on one byte order in the foreseeable future? It
  649. does not seem likely. The world cannot even decide which side of the road to
  650. drive on. The difference becomes a problem when little-endian and big-endian
  651. devices communicate with each other. It can be even more of a problem when
  652. their operating code has to be ported from one CPU to another with a different
  653. byte order.
  654. Writing a conversion routine is no problem. An experienced C programmer can
  655. whip one up in a minute. However, finding all the places where conversions are
  656. required can be difficult, unless the code was written with conversion in
  657. mind. That is where the techniques of C++ come in.
  658. First of all, a communication standard has to be established. If two devices
  659. communicate through a SCSI channel, all multi-byte values should be sent over
  660. the channel in big-endian order, which is the SCSI standard. Then conversions
  661. must be made to and from the CPU byte order, so the program can perform valid
  662. arithmetic operations on the data.
  663.  
  664.  
  665. The Types and Classes
  666.  
  667.  
  668. Listing 1 shows the header file endian.h, which contains nearly all the code.
  669. Listing 2 shows the file endian.cpp, which defines a useful union -- all the
  670. other code needed besides the header. The header defines three simple types,
  671. with names that are fairly standard:
  672. BYTE -- a single unsigned byte
  673. WORD -- a two-byte unsigned word
  674. DWORD -- a four-byte unsigned double word
  675. Variables of type WORD and DWORD are implicitly assumed to be in the order
  676. appropriate for the CPU, so the program can compute with them freely.
  677. The code also defines four classes of single and double words in specific byte
  678. orders:
  679. BEWORD -- a big endian WORD
  680. BEDWORD -- a big endian DWORD
  681. LEWORD -- a little endian WORD
  682. LEDWORD -- a little endian DWORD
  683. Of course, two of these types are substantially the same as WORD and DWORD,
  684. but the programmer does not need to know that while coding. The restrictions
  685. of C++ will prevent the program from performing arithmetic operations directly
  686. on them. This is important because such operations will become invalid when
  687. the program is ported to a CPU with a different byte order.
  688.  
  689.  
  690. Conversions
  691.  
  692.  
  693. Conversions from CPU order to big-endian or little-endian order are performed
  694. by a member function or by a class constructor. For example:
  695. LEWORD y(0xABCD);
  696. BEWORD x;
  697. x.set(0x1234);
  698. It is also possible to overload operator=, but this can cause problems in some
  699. implementations when unions containing these special types are initialized or
  700. assigned.
  701. Conversions from big endian or little endian order to CPU order are performed
  702. by a member function called value. For example, the following code adds 3 to a
  703. big endian WORD: 
  704. BEWORD x;
  705. x.set(x.value() + 3);
  706. An attempt to do this in a nonportable fashion will be flagged as a
  707. compile-time error: 
  708. BEWORD x;
  709. x = x + 3; // ERROR!
  710. In this case, Turbo C++ reports, "Operator cannot be applied to these operand
  711. type." 
  712. The compiler knows the byte order of the CPU on which its object code will
  713. run, but will not reveal it at preprocessing time. If the programmer has this
  714. information, the code can be made more efficient by defining either_BIG_ENDIAN
  715. or _LITTLE_ENDIAN (but not both!) to indicate the byte order to be used. For
  716. example, if _BIG_ENDIAN is defined, then x.set(0x1234), when x is of type
  717. BEWORD, will generate the code for a simple assignment.
  718. If neither _BIG_ENDIAN nor _LITTLE_ENDIAN is defined, the compiler will
  719. generate less efficient code that will work on any CPU. For example, if x is
  720. of type BEWORD, x.set(0x1234) will generate code that performs the following
  721. operations:
  722. y = 0x1234
  723. first byte of x = y >> 8
  724.  
  725. second byte of x = y
  726. If shifting is a particularly slow operation, it might be advisable to include
  727. a quick test for byte order at run time, and skip the shifting if the byte
  728. order of the CPU is the same as that of the word or double word being
  729. converted.
  730. If _RUN_TIME_ENDIAN is defined, the code will define a quick test, big_endian,
  731. which returns a true value (1) if it is executed on a big_endian CPU and a
  732. false value (0) otherwise. The code will also define a similar test called
  733. little_endian. These tests are used to skip the shifts where possible. In most
  734. implementations of C++, the tests involve no more code than testing a flag.
  735. Indeed, that is precisely how they are implemented. The initialized union
  736. _endian compiles with a 1 in either _endian.half[0] or _endian.half[1],
  737. depending on the byte order of the CPU.
  738. It is possible to overload operators, but it is generally more efficient to
  739. convert all multi-byte values to the CPU's byte order and use the regular
  740. operators. The only exceptions are operator== and operator!=, which do not
  741. depend on byte order as long as both operands use the same byte order, and
  742. tests against zero, which are implemented as the member functions zero and
  743. nonzero.
  744. All member functions have been defined inline, which makes them run fast and
  745. generates absolutely no code for member functions that are not called. If
  746. minimizing code size is desirable, it may be advisable to code some of them
  747. separately.
  748.  
  749. Listing 1 The File ENDIAN.H
  750. // Portable Byte Ordering in C++
  751. // by Philip J. Erdelsky
  752. // Public Domain -- No Restrictions on Use
  753.  
  754. // If the byte order of the target machine is known, include ONE of
  755. // the following statements:
  756. // #define _BIG_ENDIAN
  757. // #define _LITTLE_ENDIAN
  758.  
  759. // If the byte order of the target machine is to be determined at run
  760. // time for each conversion, include the following statement:
  761. // #define _RUN_TIME_ENDIAN
  762.  
  763. #ifndef _ENDIAN
  764. #define _ENDIAN 1
  765.  
  766. typedef unsigned char BYTE;
  767. typedef unsigned short WORD; // two-byte word
  768. typedef unsigned long DWORD; // four-byte double word
  769.  
  770. #ifdef _RUN_TIME_ENDIAN
  771.  
  772. extern union_endian_union
  773. {
  774. DWORD whole;
  775. WORD half[2];
  776. } _endian;
  777.  
  778. inline int big_endian(void) {return _endian.half[1];}
  779. inline int little_endian(void) {return _endian.half[0];}
  780.  
  781. #endif
  782.  
  783. // check for consistent parameter definitions
  784.  
  785. #ifdef _BIG_ENDIAN
  786. #ifdef _LITTLE_ENDIAN
  787. #error _BIG_ENDIAN and _LITTL