Forum: Compiler & IDEs Diagnose-Programm für Umgebungsparameter wie sizeof(int), Endianess, Alignment usw.?


von Rolf F. (Firma: G.) (benutzername0)


Lesenswert?

Ich suche ein Diagnose-Programm (im Quelltext) mit dem man die 
Umgebungsparameter der Plattform angezeigt bekommt, beispielsweise 
sizeof(int), Endianess, Alignment und anderes.
Können die Experten hier eines empfehlen?

Das Problem müssten doch abermillionen andere Programmierer schon gehabt 
haben und entsprechend müsste es doch Standard-Programme dafür geben.

von Peter II (Gast)


Lesenswert?

Rolf F. schrieb:
> Das Problem müssten doch abermillionen andere Programmierer schon gehabt
> habe

welches Problem denn?

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Rolf F. schrieb:
>> Das Problem müssten doch abermillionen andere Programmierer schon gehabt
>> habe
>
> welches Problem denn?

und wenn man wirklich die Parameter eines Compilers mal schnell braucht, 
dann schreibt man sich den 4 Zeiler mal halt eben schnell
1
#include <stdio.h>
2
3
int main()
4
{
5
  printf( "int : %d Bytes\n", (int)sizeof(int) );
6
  printf( "long: %d Bytes\n", (int)sizeof(long) );
7
8
  printf( "to be continued\n" );
9
}

das geht schneller als das Durchsuchen der Tools Verzeichnisse und sich 
daran erinnern, wie denn das Tool verflixt noch mal geheissen hat.

: Bearbeitet durch User
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Eben. Selber machen ist angesagt. Endianess zu prüfen geht leicht mit 
einer union. Alignement geht u.U. mit sizeof 
(meine_geschickt_angelegte_struct).

Man kann aber auch einfach portabel programmieren. Dann braucht man 
weder Wissen über Endianess noch über Alignments.

von Mark B. (markbrandis)


Lesenswert?

Rolf F. schrieb:
> Endianess

Das hier find ich gut:

http://esr.ibiblio.org/?p=5095

von Haro (Gast)


Lesenswert?

Es gibt Binärprotokolle die auch 2- oder 4 Byte Typen übertragen können. 
Irgendwo wird man da zwangsläufig die Endianess der Zielhardware in 
Betracht ziehen müssen, da gehts dann nicht mehr 100% portabel.

von (prx) A. K. (prx)


Lesenswert?

Haro schrieb:
> Es gibt Binärprotokolle die auch 2- oder 4 Byte Typen übertragen können.
> Irgendwo wird man da zwangsläufig die Endianess der Zielhardware in
> Betracht ziehen müssen, da gehts dann nicht mehr 100% portabel.

Du kennst Funktionen wie htonl?

von Peter II (Gast)


Lesenswert?

Haro schrieb:
> Es gibt Binärprotokolle die auch 2- oder 4 Byte Typen übertragen können.
> Irgendwo wird man da zwangsläufig die Endianess der Zielhardware in
> Betracht ziehen müssen, da gehts dann nicht mehr 100% portabel.

warum nicht?

uint16_t x = byteH<<8 | byteL

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> warum nicht?

Geht. Tempo spielt aber ab und zu doch noch eine Rolle.

von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Geht. Tempo spielt aber ab und zu doch noch eine Rolle.

wo sieht du hier ein Problem? So etwas bekommt wohl jeder aktuelle 
Compiler sinnvoll hin.

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> wo sieht du hier ein Problem? So etwas bekommt wohl jeder aktuelle
> Compiler sinnvoll hin.

Mag sein, dass manche aktuellen Compiler die entsprechende Byte-Orgie 
auch bei 4 Bytes erkennen und optimieren. Aber da man dieses Problem 
schon vor zig Jahren hatte gibt es überall dort, wo der Sockel-API 
Einzug hielt, mindestens Funktionen wie htons/ntohs und htonl/ntohl, die 
(hoffentlich) einigermassen optimiert implementiert sind (garnix, oder 
Byteswap-Befehl).

Weshalb also das Rad neu erfinden?

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Weshalb also das Rad neu erfinden?

will ich doch gar nicht.

Ich wollte nur fragen wo er ein Problem sieht
> Es gibt Binärprotokolle die auch 2- oder 4 Byte Typen übertragen können.
> Irgendwo wird man da zwangsläufig die Endianess der Zielhardware in
> Betracht ziehen müssen, da gehts dann nicht mehr 100% portabel.

wie man es löst, ist ja egal aber es geht portable.

von Heute mal nicht angemeldet (Gast)


Lesenswert?

#include <limits.h>

von Bernd K. (prof7bit)


Lesenswert?

Rolf F. schrieb:

> Das Problem müssten doch abermillionen andere Programmierer schon gehabt
> haben und entsprechend müsste es doch Standard-Programme dafür geben.

Ja, die gibt es:

* autoconf/automake

* cmake

Um mal die bekanntesten zu nennen. Mit solchen oder ähnlichen Tools wird 
dieser ganze Themenkomplex mehr oder weniger automatisiert erschlagen, 
die finden raus wie es auf der Zielplatform aussieht und konfigurieren 
dein Makefile entsprechend.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Peter II schrieb:
>> Rolf F. schrieb:
>>> Das Problem müssten doch abermillionen andere Programmierer
>>> schon gehabt habe
>>
>> welches Problem denn?
>
> und wenn man wirklich die Parameter eines Compilers mal schnell braucht,
> dann schreibt man sich den 4 Zeiler mal halt eben schnell
>
>
1
> #include <stdio.h>
2
> 
3
> int main()
4
> {
5
>   printf( "int : %d Bytes\n", (int)sizeof(int) );
6
>   printf( "long: %d Bytes\n", (int)sizeof(long) );
7
> 
8
>   printf( "to be continued\n" );
9
> }
10
>

Ok, das ist für den einfachen Fall, dass der Compiler, um den es geht, 
ein nativer ist und man das Programm einfach ausführen kann.

Bei einem Crosscompiler ist das nicht mehr ganz so einfach... Was 
hingegen auch mit einem Crosscompiler geht, ist Code präprozessieren zu 
lassen.

Handelt es sich um einen foo-gcc, dann gibt es built-in Makros für die 
meisten Typen; hier avr-gcc:
 
1
$ echo | avr-gcc -x c - -E -dM | grep SIZE | sort
2
#define __SIZEOF_DOUBLE__ 4
3
#define __SIZEOF_FLOAT__ 4
4
#define __SIZEOF_INT__ 2
5
#define __SIZEOF_LONG_DOUBLE__ 4
6
#define __SIZEOF_LONG_LONG__ 8
7
#define __SIZEOF_LONG__ 4
8
#define __SIZEOF_POINTER__ 2
9
#define __SIZEOF_PTRDIFF_T__ 2
10
#define __SIZEOF_SHORT__ 2
11
#define __SIZEOF_SIZE_T__ 2
12
#define __SIZEOF_WCHAR_T__ 2
13
#define __SIZEOF_WINT_T__ 2
14
#define __SIZE_MAX__ 65535U
15
#define __SIZE_TYPE__ unsigned int
 
...wie Basistypen definiert sind:
 
1
$ echo | avr-gcc -x c - -E -dM | grep TYPE | sort
2
#define __CHAR16_TYPE__ short unsigned int
3
#define __CHAR32_TYPE__ long unsigned int
4
#define __INT16_TYPE__ short int
5
#define __INT32_TYPE__ long int
6
#define __INT64_TYPE__ long long int
7
#define __INT8_TYPE__ signed char
8
#define __INTMAX_TYPE__ long long int
9
#define __INTPTR_TYPE__ int
10
#define __INT_FAST16_TYPE__ int
11
#define __INT_FAST32_TYPE__ long int
12
#define __INT_FAST64_TYPE__ long long int
13
#define __INT_FAST8_TYPE__ signed char
14
#define __INT_LEAST16_TYPE__ short int
15
#define __INT_LEAST32_TYPE__ long int
16
#define __INT_LEAST64_TYPE__ long long int
17
#define __INT_LEAST8_TYPE__ signed char
18
#define __PTRDIFF_TYPE__ int
19
#define __SIG_ATOMIC_TYPE__ char
20
#define __SIZE_TYPE__ unsigned int
21
#define __UINT16_TYPE__ short unsigned int
22
#define __UINT32_TYPE__ long unsigned int
23
#define __UINT64_TYPE__ long long unsigned int
24
#define __UINT8_TYPE__ unsigned char
25
#define __UINTMAX_TYPE__ long long unsigned int
 
...Endianess:
 
1
$ echo | avr-gcc -x c - -E -dM | grep END | sort
2
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
3
#define __FLOAT_WORD_ORDER__ __ORDER_LITTLE_ENDIAN__
4
#define __ORDER_BIG_ENDIAN__ 4321
5
#define __ORDER_LITTLE_ENDIAN__ 1234
6
#define __ORDER_PDP_ENDIAN__ 3412
7
D:\C\avrtest>
 
Weiß man nicht, um welchen Compiler es sich handelt, scannt man stderr 
auf Ausgabe -- zumindest wenn sich der Compiler halbwegs an den Standard 
hält:

Keine Diagnostic --> der Test trifft zu.
Diagnostic --> der Test trifft nicht zu.

Beispiel:
1
int a [sizeof (int) == 2 ? 1 : -1];

Bei Fehler ist int nicht 2 Bytes groß, ansonsten ist es 2 Bytes groß; 
wobei sizeof (Byte) = sizeof (char) sei.  Das ist z.B. der Ansatz, den 
configure bzw. autoconf wählt.

Für Alignment ist das alles schon was hakeliger. Evtl. geht dieser Test:
 
1
int a[sizeof (struct {char a; int b;}) == 8 ? 1 : -1];
 
D.h. unter der Annahme, dass das Alignment des int in einer Struktur 
Rückschlüsse auf das Alignment von int zulässt.  Hier ist man auch dann 
nicht besser dran, wenn man das Programm ausführen kann, denn das 
Ergebnis basiert auf der gleichen Annahme.

Das einzige was dann hilft, ist die Compiler-Doku bzw. (E)ABI zu lesen, 
wo "Implementation Defined Behaviour" dokumentiert ist.

Ob es einen sicheren Compilezeit-Test auf Endianess gibt weiß ich nicht; 
bisher ist mir keiner eingefallen. Ideen?

von Haro (Gast)


Lesenswert?

A. K. schrieb:
> Haro schrieb:
> Es gibt Binärprotokolle die auch 2- oder 4 Byte Typen übertragen können.
> Irgendwo wird man da zwangsläufig die Endianess der Zielhardware in
> Betracht ziehen müssen, da gehts dann nicht mehr 100% portabel.
>
> Du kennst Funktionen wie htonl?

Ja, die werden aber nicht vom C Standard definiert, stehen damit also 
nicht automatisch auf jedem System mit C Compiler zur Verfügung. Die AVR 
libc bringt sie beispielsweise nicht mit.
Selber schreiben ist zwar trivial, aber Code der darauf angewiesen ist 
ist damit jedenfalls nicht mehr uneingeschränkt portabel.

von Haro (Gast)


Lesenswert?

> warum nicht?
>
> uint16_t x = byteH<<8 | byteL

In deinem Beispiel mit byteH und byteL natürlich klar.

Üblicherweise gelangen die Daten aber Byteweise ins System und liegen 
erstmal irgendwo in einem Puffer myBuffer[MY_BUFFER_SIZE].
Das Protokoll enthält Header, Kommandos, und irgendwie auch die 
Nutzdaten.

Kannst du nun für alle Systeme uneingeschränkt festlegen, dass immer 
myBuffer[20] an die höherwertige Adresse und myBuffer[21] an die 
niederwertige Adresse eines 16bit Typen muss?

von Haro (Gast)


Lesenswert?

Haro schrieb:
> warum nicht?
> uint16_t x = byteH<<8 | byteL
>
> In deinem Beispiel mit byteH und byteL natürlich klar.
>
> Üblicherweise gelangen die Daten aber Byteweise ins System und liegen
> erstmal irgendwo in einem Puffer myBuffer[MY_BUFFER_SIZE].
> Das Protokoll enthält Header, Kommandos, und irgendwie auch die
> Nutzdaten.
>
> Kannst du nun für alle Systeme uneingeschränkt festlegen, dass immer
> myBuffer[20] an die höherwertige Adresse und myBuffer[21] an die
> niederwertige Adresse eines 16bit Typen muss?

Vergiss diesen Beitrag, es ist spät...

von (prx) A. K. (prx)


Lesenswert?

Gewöhnlich legt man für das Protokoll eine bestimmte Bytereihenfolge 
fest, unabhängig davon wer mit wem redet. Bei Seiten passen sich dann 
dieser Definition an.

: Bearbeitet durch User
von Rolf F. (Firma: G.) (benutzername0)


Lesenswert?

Frank M. schrieb:

> Man kann aber auch einfach portabel programmieren. Dann braucht man
> weder Wissen über Endianess noch über Alignments.

Das ist aber ineffizient.
Beispielsweise kann mam uint64_t verwenden, aber allein damit kennt man 
die Endianess nicht, die bei Unions wichtig ist. Bei vielen 
ARM-Prozessoren kann man ja einstellen ob Big- oder Little Endian 
(vielleicht auch PDP Endian).
Und es gibt Plattformen wie MSP430, bei denen die Operationen damit 
deutlich langsamer als mit uint16_t sind.
Außerdem geht es hier um das Wissen über eine Plattform, wozu nicht nur 
das Datenblatt der CPU gehört sondern auch das was Compiler, Assembler, 
Linker usw. auch tatsächlich können.
Was man mit dem Wissen macht ist eine andere Sache. Mir geht es erstmal 
um die Diagnose.

von Rolf F. (Firma: G.) (benutzername0)


Lesenswert?

Mark Brandis schrieb:
> Rolf F. schrieb:
>> Endianess
>
> Das hier find ich gut:
>
> http://esr.ibiblio.org/?p=5095

Damit findet man aber PDP Endian und andere nicht.

Besser ist:
1
// Estimate the main endianess.
2
// Caution: There are more platform dependencies (implementation-dependent
3
// things), e. g. the alignment rules and the size of a Byte, which can be
4
// found as CHAR_BIT in limits.h.
5
#  ifndef LITTLE_ENDIAN
6
#    define LITTLE_ENDIAN 1
7
#  endif
8
#  ifndef PDP_ENDIAN
9
#    define PDP_ENDIAN 2
10
#  endif
11
#  ifndef BIG_ENDIAN
12
#    define BIG_ENDIAN 3
13
#  endif
14
#  ifndef UNKNOWN_ENDIAN
15
#    define UNKNOWN_ENDIAN 0
16
#  endif
17
uint16_t endianess ()
18
{
19
  union
20
  {
21
    uint64_t uli;
22
    uint32_t ui[2];
23
    uint16_t usi[4];
24
    uint8_t uc[8];
25
  } u_end =
26
  {
27
  1};
28
  if (1 == u_end.uc[0])
29
    return (LITTLE_ENDIAN);
30
  else
31
  {
32
    if (1 == u_end.usi[1])
33
      return (PDP_ENDIAN);
34
    else
35
    {
36
      if (1 == u_end.uc[7])
37
        return (BIG_ENDIAN);
38
    }
39
  }
40
  return (UNKNOWN_ENDIAN);
41
}

: Bearbeitet durch User
von Rolf F. (Firma: G.) (benutzername0)


Lesenswert?

Hier ist mal ein Anfang mit einem kleinen Testprogramm:

[CODE]
// test program for platform dependent things like type sizes, 
endianess, alignment, ...

#include <stdio.h>
#include <stdint.h>
#include <limits.h>

// Estimate the main endianess.
void endianess ()
{
  union
  {
    uint64_t uli;
    uint32_t ui[2];
    uint16_t usi[4];
    uint8_t uc[8];
  } u_end =
  {
  1};
  printf ("Endianess: ");
  if (1 == u_end.uc[0])
  {
    printf ("LITTLE_ENDIAN\n");
    return;
  }
  else
  {
    if (1 == u_end.usi[1])
    {
      printf ("PDP_ENDIAN\n");
      return;
    }
    else
    {
      if (1 == u_end.uc[7])
      {
        printf ("BIG_ENDIAN\n");
        return;
      }
    }
  }
  printf ("UNKNOWN_ENDIAN\n");
  return;
}

int main ()
{
  //clrscr();
  endianess ();
  printf ("Size of byte in bits is %d\n", CHAR_BIT);
  printf ("Size of char (in bytes) is %d\n", sizeof (char));
  printf ("Size of wide char is %d\n", sizeof (wchar_t));
  printf ("Size of short int is %d\n", sizeof (short int));
  printf ("Size of int is %d\n", sizeof (int));
  printf ("Size of long int is %d\n", sizeof (long int));
  printf ("Size of long long int is %d\n", sizeof (long long int));
  printf ("Size of pointer is %d\n", sizeof (int *));
  printf ("Size of long is %d\n", sizeof (float));
  printf ("Size of double is %d\n", sizeof (double));
  printf ("Size of long double is %d\n", sizeof (long double));

//sizeof struct test{char c, long long int lli;

  return 0;
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Rolf F. schrieb:
> Hier ist mal ein Anfang mit einem kleinen Testprogramm:

Das ist nicht portabel da ungültiger Code :-)

von Erwin M. (nobodyy)


Lesenswert?

Johann L. schrieb:
> Rolf F. schrieb:
>> Hier ist mal ein Anfang mit einem kleinen Testprogramm:
>
> Das ist nicht portabel da ungültiger Code :-)

Klar, das ist ja nur der Quelltext.
Ein Programm wird daraus erst mit Präprozessor, Compiler, Assembler, 
Linker usw..
Und das ist für eine hosted Implementation. Freestanding ist es 
schwieriger, weil es da meist kein printf gibt.

Und schöner wäre es wenn schon der Präprozessor die Werte ausgeben 
würde, über #warning.
Aber geht das überhaupt?

von Erwin M. (nobodyy)


Lesenswert?

Hier gibt es unten auf der Seite ein Test-Programm und mit weniger 
Umfang die Autoconf-Einträge:

https://wiki.debian.org/ArchitectureSpecificsMemo

Unter Ubuntu liefert mir das auf meinem PC:

Size of byte in bits is 8
Size of char (in bytes) is 1
Size of wide char is 4
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(long long) = 8
sizeof(float) = 4
sizeof(double) = 8
sizeof(long double) = 16
sizeof(void *) = 8
byte order = little endian
char signedness = signed
stack = grows down

Das long double war früher nur 10 Byte groß und wide Char nur 2.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Erwin Meyer schrieb:
> Johann L. schrieb:
>> Rolf F. schrieb:
>>> Hier ist mal ein Anfang mit einem kleinen Testprogramm:
>>
>> Das ist nicht portabel da ungültiger Code :-)
>
> Klar, das ist ja nur der Quelltext.

...dessen Verhalten im C-Standard festgelegt ist.  Diese bezeichnet das 
Verhalten des Programms als "Undefined Behavior".  Hier im Forum wurde 
das schon X mal durchgekaut.  Im Enfeffekt sid es ähnliche Regeln wie 
sie auch für Strict Aliasing gelten.

GCC unterstützt deinen Code als Spracherweiterung und sichert das, was 
du erwartest, auch in seiner Dokumentation zu.  Der Code ist also nur 
gültig, weil wir hier im GCC-Forum sind :-)  Mit anderen Compilern geht 
du aber durchaus baden...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.