Writing portable code regarding the processor architecture/id

From Free Pascal wiki
Revision as of 21:22, 29 September 2007 by Adezm (talk | contribs) (→‎Endianness)
Jump to navigationJump to search

Ada beberapa isu utama saat menulis kode yang portabel sehubungan dengan arsitektur prosesor: endianness dan prosesor 32 vs. 64 bit.


Endianness adalah cara bagaimana nilai lebih besar dari sebuah byte (misalnya 16/32/64-bit integers) disimpan oleh prosesor.

Free Pascal mendukung prosesor dengan dua jenis endianness:

  1. Menyimpan nilai terendah pada alamat terendah; longint(4) dienkode sebagai 04 00 00 00 (little endian)
  2. Menyimpan nilai tertingi pada alamat terendah; longint(4) dienkode sebagai 00 00 00 04 (big endian)

catatan samping:

Endian tengah, juga disebut endian campuran, prosesor jarang sekarang. Yang terkenal, tapi sekarang menjadi historis, prosesor endian menengah adalah PDP-11 dari DEC.

Endianness adalah pilihan umum yang diberikan per keluarga prosesor, tapi beberapa keluar prosesor dapat berupa endian besar atau endian kecil pada mainboard yang disertakannya (ARM, PPC).

Prosesor endian kecil yang paling terkenal adalah keluarga x86, keluar prosesor yang digunakan dalam PC, dan yang terbarunya x86-64. Prosesor umum endian besar adalah PPC (biasanya, lihat catatan di atas), dan m68k, banyak sistem lebih lama seperti misalnya HP3000 minikomputer, dan mainframes seperti IBM 370 (seri Z).

Karena TCP/IP menetapkan bahwa semua struktur header protokol yag bejalan di atas kawat harus endian besar, maka notasi ini kadang-kadang dirujuk sebagai urutan jaringan.

Endianness adalah penting

  1. ketika bertukar data antara arsitektur yang bebeda
  2. ketika mengakses data kadang-kadang sebagai (sebuah array dari) tipe lebih besar, seperti integer, dan kadangkala sebagai (sebuah array dari) byte.

Contoh yang terakhir:

     Q = RECORD
         case boolean of
             true: (i:integer);
             false: (p:array[1..4] of byte)
Var x:^Q ;
     if x^.p[1]=5 then
         writeln(x^.p[1],' Your machine is Little Endian')
         if x^.p[4]=5 then
             writeln(x^.p[1],' Your machine is Big Endian')
             writeln(x^.p[1],' ',x^.p[2],' ',x^.p[3],' ',x^.p[4],' Your machine''s endianness is indeterminate; please report the results to the compiler development team');
    {Make it wait so we can see the results }
     write('Press enter when you finish reading this ');

Pada mesin endian kecil (PCs), kode di atas akan menulis 5 (karena longint(5) disimpan sebagai 05 00 00 00 dalam memori), sementara pada mesin endian besar (contohnya Powermacs) ia akan menulis 0 (karena longint(5) disimpan sebagai 00 00 00 05 dalam memori). (Jika anda mendapatkan laporan mesin anda adalah menengah, silahkan laporkan pada halaman wiki ini apa yang tidak didapatkan dan didapatkan prosesor ini!)

Untuk menentukan endianness dari sebuah prosesor, gunakan ENDIAN_BIG atau ENDIAN_LITTLE (atau FPC_LITTLE_ENDIAN dan FPC_BIG_ENDIAN mulai dari versi 1.9) mendefinisikan bahwa didefinisikan oleh freepascal secara otomatis tergantung pada prosesor.


Some processors will allow improperly aligned data but with reduced efficiency (IBM 370/zSeries). Some processors generate hardware processor exceptions when data is badly aligned (e.g. Alpha or ARM). Sometimes the hardware exceptions are caught and fixed using emulation by the OS, but this is very slow, and should be avoided. This can also cause records to have different sizes, so always use sizeof(recordtype); as size of a record. If you define a packed record, try to ensure that data is naturally aligned, if possible. Some processors only have alignment requirements for certain types of data, like floating point (e.g. older PowerPCs).

To check if the CPU requires proper alignment, check the FPC_REQUIRES_PROPER_ALIGNMENT (version 1.9 and higher) define. On 32 Bit CPUs this usually means that data up to a size of 4 must be naturally aligned. If you want to access unaligned data, use the move procedure to move it to an aligned location before processing it. The move procedure takes care of unaligned data and handles it properly.

There are multiple strategies for aligning:

  • align every field on a multiple of a certain value (typically a power of two, 1,2,4,8. 1 is equivalent to "packed")
  • pad before every field such that it is aligned on a multiple of its size (so a longint on 4, an int64 on 8 bytes etc). This is typically done by C compiler, which is why FPC calls it {$packrecords C}.

(For arrays or nested records, the size of their largest sub unit is used)

Mac OS X {$packrecords C} seems to pad the entire record at the end to make it a certain size. This is still being investigated, and probably will be fixed in compiler.

32 Bit vs. 64 Bit

To achive maximum compatiblity with older code, FPC doesn't change the size of predefined data types like integer, longint or word when changing from 32 to 64 Bit. However, the size of a pointer is 8 bytes on a 64 bit architecture so constructs like longint(pointer(p)) are doomed to crash on 64 bit architectures. However, to allow you to write portable code, the FPC system unit introduces the types PtrInt and PtrUInt which are signed and unsigned integer data types with the same size as a pointer.

Keep in mind that the size change of the "pointer" type also affects record sizes. If you allocate records with fixed sizes, and not with new or with getmem (<x>,sizeof(<x>)), this will have to be fixed.

This is in line with most open Unix platforms. In the commercial world, there are some exceptions like Tru64, with is ILP64

Konvensi pemanggilan

  • For IBM 370 and zSeries, see the ZSeries page for further discussion.

In general avoid relying on internal knowledge, like if a pass by const is on the stack or by value.




navigation bar: data types
simple data types

boolean byte cardinal char currency double dword extended int8 int16 int32 int64 integer longint real shortint single smallint pointer qword word

complex data types

array class object record set string shortstring