Endianness
Doch selbst Prozessoren mit gleicher Wortbreite unterscheiden sich noch so grundlegend, dass es zu Portierungsproblemen kommt. Unterschiedliche Prozessoren legen Daten nämlich auch anders im Speicher ab. Denn unglücklicherweise gibt es gleich zwei Formate, um 16-, 32- oder 64-Bit-Wörter im Speicher zu repräsentieren.
Abbildung 3 zeigt, dass das Little-Endian-Format das niederwertige Byte eines Wortes auf die niederwertige Adresse legt. So macht es etwa der klassische PC mit x86-Prozessoren. Eine Sun-Workstation mit Sparc-Prozessor legt dagegen das niederwertige Byte an die höherwertige Adresse. Es gibt sogar Prozessoren, die beides können.

|
Abbildung 3: Prozessoren legen die einzelnen Bytes eines Datenwortes unterschiedlich im Speicher ab. Beim Little-Endian-Format steht das niederwertige Byte an der niederwertigen (»0«), bei Big Endian dagegen an der höherwertigen Adresse.
|
Der Endian-Unterschied wird dann zum Problem, wenn zwei oder mehr Prozessoren, die unterschiedliche Datenablageformate verwenden, auf denselben Datensatz zugreifen. Bei vernetzten Rechnersystemen ist das ohnehin oft der Fall. Das Problem kann aber auch beim Zugriff auf intelligente Hardware auftreten, deren Anbindung zumeist über ein Speicherinterface (Dual-Port-RAM, Shared Memory) realisiert ist. Gleiches gilt beim Speichern von Daten auf einer Festplatte - spätestens seit USB 2.0 und Firewire sind diese portabel und leicht von einem zum anderen Rechner zu transportieren.
Byte-Swapping sparen
Zur Lösung des Problems bietet Linux vom Ablageformat des Prozessors unabhängige Datentypen an: »__le16«,» __le32«, »__le64« und »__be16«, »__be32«, »__be64« (siehe Tabelle 1). Außerdem kann der Programmierer auf Makros zurückgreifen, die zwischen den Formaten konvertieren (siehe Tabelle 2).
|
|
|
Erklärung
|
Funktionsnamen
|
|
Umwandlung aus dem Host- ins Netzwerk-Format (Big Endian)
|
__be16 htons( __u16 value ), __be32 htonl( __u32 value )
|
|
Umwandlung aus dem Netzwerk- (Big Endian) ins Host-Format
|
__u16 ntohs( __be16 value ), __132 ntohl( __be32 value );
|
|
Umwandlung aus dem Host- ins Little-Endian-Format
|
__le16 cpu_to_le16( __u16 value ), __le32 cpu_to_le32( __u32 value ), __le64 cpu_to_le64( __u64 value )
|
|
Umwandlung aus dem Host- ins Little-Endian-Format, das Ergebnis
der Wandlung wird in der ursprünglichen Variablen abgelegt (in situ)
|
void cpu_to_le16s( __u16 *value ), void cpu_to_le32s( __u32 *value ), void cpu_to_le64s( __u64 *value )
|
|
Umwandlung aus dem Host- ins Big-Endian-Format
|
__be16 cpu_to_be16( __u16 value ), __be32 cpu_to_be32( __u32 value ), __be64 cpu_to_be64( __u64 value )
|
|
Umwandlung aus dem Host- ins Big-Endian-Format, das Ergebnis
der Wandlung wird in der ursprünglichen Variablen abgelegt (in situ)
|
void cpu_to_be16s( __u16 *value ), void cpu_to_be32s( __u32 *value ),
void cpu_to_be64s( __u64 *value )
|
|
Umwandlung einer Little-Endian-Variablen ins Host-Format
|
__u16 le_to_cpu16( __le16 value ), __u32 le_to_cpu32( __le32 value ), __u64 le_to_cpu64( __le64 value )
|
|
Umwandlung einer Little-Endian-Variablen ins Host-Format, das Ergebnis
wird in der Variablen selbst abgelegt (in situ)
|
void le_to_cpu16s( __le16 *value ), void le_to_cpu32s( __le32 *value ),
void le_to_cpu64s( __le64 *value )
|
|
Umwandlung einer Big-Endian-Variablen ins Host-Format
|
__u16 be_to_cpu16( __be16 value ), __u32 be_to_cpu32( __be32 value ), __u64 be_to_cpu64( __be64 value )
|
|
Umwandlung einer Big-Endian-Variablen ins Host-Format, das Ergebnis
wird in der Variablen selbst abgelegt (in situ)
|
void be_to_cpu16s( __be16 *value ), void be_to_cpu32s( __be32 *value ),
void be_to_cpu64s( __be64 *value )
|
Damit bei dieser Umwandlung nicht bereits vorher feststehen muss, ob der verwendete Prozessor ein Little- oder ein Big-Endian-Format unterstützt, wandeln sie immer in das CPU- oder Host-Format respektive aus dem CPU- oder dem Host-Format. Dabei ist natürlich berücksichtigt, ob die CPU selbst das Zielformat unterstützt. Dann wird beim Kompilieren der Wert ohne Byte-Swapping übernommen (siehe »__cpu_to_le32(x)« in Listing 2 , Zeile 2).
01 ...
02 #define __cpu_to_le32(x) ((__u32)(x))
03 #define __le32_to_cpu(x) ((__u32)(x))
04 #define __cpu_to_le16(x) ((__u16)(x))
05 #define __le16_to_cpu(x) ((__u16)(x))
06 #define __cpu_to_be64(x) __swab64((x))
07 #define __be64_to_cpu(x) __swab64((x))
08 #define __cpu_to_be32(x) __swab32((x))
09 #define __be32_to_cpu(x) __swab32((x))
10 ...
|
Die Makros, die im Netzwerkbereich zum Einsatz kommen, heißen: »htons()« (host to network short), »htonl()« (host to network long), »ntohs()« (network to host short) und »ntohl()« (network to host long). Ein Makro »htonc()« (host to char) gibt es nicht, denn das Problem tritt nur bei Variablen auf, die 16, 32 oder 64 Bit umfassen. Der Name Htonl ist übrigens irreführend: Diese Funktion wandelt das Host-Format in ein 32-Bit-Wort (Integer). Wäre es wirklich ein »long«, käme es zu Problemen mit allen 64-Bit-Maschinen. Das Netzwerkformat ist traditionell vom Typ Big Endian. Auf dem x86-PC müssen daher alle Wörter in den Protokollheadern gedreht werden. Eine Sun-Workstation mit Sparc-Prozessor kann darauf verzichten.
Außerhalb der Netzwerkprogrammierung benutzt der Linux-Kernel die Makros »cpu_to_leX()«, »cpu_to_leXs()«, »cpu_to_beX()« und »cpu_to_beXs()« (siehe Tabelle 2), die auch 64 Bit breite Variablen unterstützen. Das angehängte »s« bei einigen der Makros steht für "in situ". Diese Makros wandeln direkt die Variable selbst. Deshalb besitzen sie keinen Rückgabewert und bekommen nicht eine Kopie, sondern die Adresse der Variablen übergeben.
Das Makro »htons()« entspricht damit der Funktion »cpu_to_be16()«, »htonl()« entspricht »cpu_to_be32()«. Wie man mit Hilfe der Datentypen und Makros programmiert, demonstriert der Kernelcode, der das Ext-2-Filesystem realisiert. Einen Ausschnitt daraus zeigt Listing 3.
01 ...
02 struct ext2_super_block {
03 __le32 s_inodes_count; /* Inodes count */
04 __le32 s_blocks_count; /* Blocks count */
05 __le32 s_r_blocks_count; /* Reserved blocks count */
06 __le32 s_free_blocks_count; /* Free blocks count */
07 __le32 s_free_inodes_count; /* Free inodes count */
08 __le32 s_first_data_block; /* First Data Block */
09 __le32 s_log_block_size; /* Block size */
10 __le32 s_log_frag_size; /* Fragment size */
11 __le32 s_blocks_per_group; /* # Blocks per group */
12 __le32 s_frags_per_group; /* # Fragments per group */
13 __le32 s_inodes_per_group; /* # Inodes per group */
14 __le32 s_mtime; /* Mount time */
15 __le32 s_wtime; /* Write time */
16 __le16 s_mnt_count; /* Mount count */
17 __le16 s_state; /* File system state */
18 ...
19 #define EXT2_HAS_COMPAT_FEATURE(sb,mask)
20 ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
21 #define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)
22 ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
23 ...
|
| Whitepaper |
|
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele
Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.
Download PDF (Registrierung erforderlich)
|
|
The Role of Open Source in Data Integration
Obwohl in den letzten Jahren viele technische Fortschritte erzielt werden konnten, verfügen die meisten Datenintegrationsprozesse nach wie vor nur über eine sehr begrenzte Automatisierung. Das vorliegende White Paper von dem Industry Analyst Mark Madson wird zunächst ein grundlegendes Verständnis von Daten Integration vermitteln, die Vorzüge von Open Source Lösungen für Daten Integration erläutern und Ihnen professionelle Empfehlungen geben, damit Sie Ihre Integrationsjobs noch einfacher und produktiver gestalten können.
Download PDF (Registrierung erforderlich)
|
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links"
nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedrucken Fassung entsprechen.
|