home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / muuglines / source / softport / softpor2.txt < prev   
Text File  |  1993-05-08  |  7KB  |  158 lines

  1. Writing Software for Portability, Part 2
  2.  
  3. By Gilbert Detillieux, Info West Inc.
  4.  
  5. Last time, we looked at how to structure a program to
  6. improve portability. By breaking it up into small,
  7. independent modules, and isolating system specific code to
  8. just a few low-level modules, you make it more portable.
  9. Even more important to assure portability is the way we use
  10. data structures and data types.  We will now look at certain
  11. considerations in using data in memory, and more
  12. importantly, how to use them in data files.
  13.  
  14. Data Types and Structures in Memory
  15.  
  16. Abstract data types can be used in many languages, to help
  17. clarify or restrict the processing we do on that data.  We
  18. also can make use of this on data whose representations may
  19. change, to simplify such changes.  In C, system header files
  20. define many such data types (time_t, uid_t, etc.), so we
  21. don't need to worry about the internal representation, which
  22. may change from system to system.  Likewise, we also can
  23. define our own data types (e.g., typedef long int
  24. acctnum_t).
  25.  
  26. You should never make assumptions about the size of data
  27. types and objects in memory, as these are machine (and
  28. compiler) specific. It may not even be safe to assume that a
  29. character takes one byte, if your code is to support
  30. international character sets.  Also use named constants for
  31. array sizes and counts.  If the system headers define some
  32. of these (buffer sizes, maximum number of files), use them;
  33. otherwise, define your own. In C, always use "sizeof" to
  34. specify sizes, when you need the size of a variable. For
  35. example, use malloc(NCHRS*sizeof(char)) rather than
  36. malloc(80) -- hard-coded constants for sizes are always a
  37. sign of trouble.
  38.  
  39. For structured data types, there are some extra
  40. considerations.  Element sizes, alignment of elements and
  41. padding can all vary with machine or compiler.  Don't assume
  42. padding is done or not, or how it's done.  With unions
  43. (variant records in Pascal), don't assume a particular
  44. alignment of the various members.  Of course, you can't
  45. easily determine the overall size of a data structure in a
  46. portable way (other than using "sizeof" in C).  If you're
  47. concerned about keeping the size of structures down to a
  48. minimum, you can assume that the best way to do that is to
  49. put all the largest elements first, then work your way down.
  50. This will reduce the amount of padding that might be
  51. introduced, and shouldn't hinder portability in any way.
  52. (In C, it's probably safe to assume the following size
  53. order: doubles, floats, pointer types, longs, ints, shorts,
  54. then chars.)
  55.  
  56. There might be restrictions on how you can allocate data,
  57. and the size that you can allocate.  Avoid allocating data
  58. in a way that isn't supported by all compilers (for example,
  59. initialized automatic arrays are supported by some compilers
  60. but aren't standard, and register types supported can vary
  61. with compilers).  Some architectures have restrictions on
  62. the size of particular objects -- automatic variables may be
  63. restricted by the size of a stack frame, or static or
  64. dynamic data may be restricted by the maximum size of a data
  65. segment.
  66.  
  67. Data File Formats
  68.  
  69. All this data has to come from somewhere, and may have to go
  70. somewhere else.  This usually means data files.  You may
  71. have to design your own data file formats, and these should
  72. be designed with portability in mind too.  This should be
  73. based on usage -- decide what data must be kept, for what
  74. purpose, and for how long, then define your format
  75. accordingly. Consider using text files for permanent data
  76. storage, as this is not only far more portable, but more
  77. versatile, flexible, and maintainable. There are lots of
  78. existing programs that you can use to edit, filter, search,
  79. and sort these files, and their format is less tied to
  80. program code changes.
  81.  
  82. Use binary files only if you have to, due to space or time
  83. constraints (i.e. if you need a more compact representation,
  84. or if conversion to/from internal representation would be
  85. too slow).  Clearly define the data types you are using,
  86. their size, representation, and even bit and byte ordering.
  87. Unlike for data types in memory, where it was better not to
  88. make assumptions about internal representation, here we must
  89. know exactly how everything is stored, so the data can be
  90. treated consistently, regardless of which program, machine,
  91. or operating system is involved.
  92.  
  93. For data structures in files, use explicit data types.  (In
  94. C, use short int, or long int, rather than just int, which
  95. is more machine specific.) Avoid automatic padding between
  96. elements by ordering them carefully.  Or you might want to
  97. introduce explicit pad bytes to force a particular
  98. alignment; this also allow for growth if you have to add new
  99. elements later.  Define clearly any assumptions you make
  100. about element sizes and offsets, and test this out with the
  101. various compilers you will use.
  102.  
  103. A Little Bit of Magic
  104.  
  105. It's a good idea to start each file with a "magic number" or
  106. "magic string" which can be used to identify uniquely the
  107. type of a file.  The value you pick is arbitrary, but should
  108. be long enough (four bytes or more), and unique.  If you use
  109. an integer magic number, you can use the bit pattern in your
  110. code to determine the bit and byte ordering in the file
  111. automatically (e.g. 1234 v.s. 4321).  A magic string is
  112. perhaps more portable, and can be used for both text files
  113. (e.g. "%!" in PostScript files) or binary files (e.g. GIF87
  114. in GIF files).
  115.  
  116. Version numbers in files are useful as well, to identify
  117. variations in a file's format.  A major version number
  118. change could indicate a significant format change (or you
  119. might want to change the magic number if the files are
  120. incompatible), while a minor version number change would
  121. indicate a small change that doesn't affect the format (e.g.
  122. new data stored in former pad bytes).  Version numbers also
  123. could indicate the presence or absence of sections, allowing
  124. changes and additions to the file's contents while still
  125. maintaining compatibility.
  126.  
  127. Avoiding Obsolescence
  128.  
  129. As much as possible, your programs should handle all file
  130. versions, so old data files aren't made obsolete by program
  131. changes.  If it's feasible, data files can be converted on
  132. the fly when your program loads an older file, or one from a
  133. different system.  Failing that, conversion programs should
  134. be provided, to support file formats for all versions,
  135. systems, and machines.  Remember that data files are likely
  136. to outlive the programs that created them, and it may be
  137. important to continue to support them.
  138.  
  139. In a way, file formats are like protocols -- you should stick
  140. to a standard, define it clearly, and plan for future
  141. growth.  Use industry standards where possible (e.g. ASCII
  142. or ISO character sets, IEEE floating point format, Sun's XDR
  143. standards), or define your own if you have to, but do so
  144. carefully.  And most importantly, document everything you do
  145. (data types, structures, file formats, versions supported,
  146. conversions, defaults for missing data, etc.), keep these
  147. documents consistent with your code, and make them available
  148. to everyone who needs to know.
  149.  
  150. There is no simple formula to assure portability of software
  151. and data. Choosing languages and systems that are portable
  152. is an important step, but that isn't enough.  You have to
  153. plan for future growth in machines, systems, and in your own
  154. software.  Think about portability from the start.  Define
  155. and stick to standards, but also be flexible -- use an open-ended
  156. design to allow for unforeseen changes.  And document,
  157. document, document!
  158.