Forum: Compiler & IDEs Mal wieder ne Frage zu "volatile"


von klaus (Gast)


Lesenswert?

Hallo zusammen,

wie verhält sich GCC bei eingeschalteter Optimierung wenn eine volatile 
Variable mehrfach hintereinander gelesen wird. Also beispielsweise:
1
#define REG (*((volatile unsigned int*)0x1234))
2
3
unsigned int temp;
4
5
temp = REG;
6
temp = REG;

Ist hierbei sichergestellt, dass das Register auch mehrfach gelesen wird 
?

Der Compiler könnte z.B. ja denken, dass das erste Lesen unnötig ist, da 
im zweiten Schritt der gelesene Wert überschrieben wird...

von Karl H. (kbuchegg)


Lesenswert?

klaus schrieb:

> Der Compiler könnte z.B. ja denken, dass das erste Lesen unnötig ist, da
> im zweiten Schritt der gelesene Wert überschrieben wird...

Genau das ist der Zweck von 'volatile'.
Den Compiler daran zu hindern, genau das zu denken.

volatile sorgt dafür, dass jeder Zugriff auch exakt so ausgeführt wird, 
wie du ihn hingeschrieben hast.

von klaus (Gast)


Lesenswert?

Gilt dies auch für das Lesen eines Registers wenn der gelesene Wert nie 
verwendet wird?

Aus der Definition die ich gefunden habe geht das nicht explizit hervor:

"Das Schlüsselwort volatile teilt dem Compiler mit, daß die mit name 
bezeichnete Variable mit dem Datentyp typ durch Ereignisse außerhalb der 
Kontrolle des Programms verändert werden kann."

von Karl H. (kbuchegg)


Lesenswert?

klaus schrieb:
> Gilt dies auch für das Lesen eines Registers wenn der gelesene Wert nie
> verwendet wird?


Jeder Zugriff muss so gemacht werden, wie du ihn hingeschrieben hast!
Ausnahmslos jeder! Egal wie sinnlos er für den Compiler und seine 
Datenflussanalyse auch aussehen mag.

volatile bedeutet für den Compiler: No optimizations allowed!

von Stefan B. (stefan) Benutzerseite


Lesenswert?

klaus schrieb:

> Gilt dies auch für das Lesen eines Registers wenn der gelesene Wert nie
> verwendet wird?

Es wäre übel, wenn die Anweisung dann entfallen würde.

Klassischer Anwendungsfall z.B. UDR muss beim UART-Empfang auf dem AVR 
ausgelesen werden. Nach dem Auslesen kann man es wegschmeissen (nicht 
weiterverwenden), aber Lesen muss man es, weil ansonsten z.B. der 
Empfangsinterrupt immer wieder käme.

Ein
{
  ...
  {
    unsigned int dummy = UDR;
  }
  ...
}

muss in Programmanweisung(en) übersetzt werden, selbst wenn das lokale 
dummy nie verwendet wird.

von klaus (Gast)


Lesenswert?

Wäre auch meine eigene Einschätzung gewesen. Bei der LPC2000 Serie hatte 
ich mit ähnlichen Registern zu tun. Habe folgendes gefunden, da stehts 
explizit:

"Objects declared as volatile are not used in certain optimizations 
because their values can change at any time. The system always reads the 
current value of a volatile object at the point it is requested, even if 
a previous instruction asked for a value from the same object. Also, the 
value of the object is written immediately on assignment."


Danke für eure Antworten!

von STK500-Besitzer (Gast)


Lesenswert?

>unsigned int dummy = UDR;
1
UDR;

könnte da sogar reichen...

von Krishna (Gast)


Lesenswert?

>könnte da sogar reichen...
wäre aber was für einen obscated c contest

von horst (Gast)


Lesenswert?

REG ist volatile, muß also beide Male gelesen werden.
temp ist aber nicht volatile.
So wie ich das sehe, könnte der Optimierer daraus zwei x Lesen und nur 1 
x Schreiben machen.

von Peter D. (peda)


Lesenswert?

STK500-Besitzer schrieb:
>
1
> UDR;
2
>
>
> könnte da sogar reichen...


Ich fall vom Stuhl, das tuts!

Ist das auch wirklich im C-Standard garantiert, daß dann ein Lesezugriff 
erfolgen muß?


Peter

von Karl H. (kbuchegg)


Lesenswert?

Sicher. Das ist eine Expression wie jede andere auch.

   3 + 4;

ist Standard-C.

Dies geht deshalb, weil in C ja auch eine Zuweisung eine Expression ist, 
die ein Ergebnis liefert. So gesehen besteht in C für den Compiler kein 
Unterschied zwischen

     a;
und
     a = 5;

beides sind Ausdrücke, die einen Wert liefern. Nur hat der 2te Ausdruck 
noch den Nebeneffekt, dass während seiner Auswertung a noch einen neuen 
Wert bekommt :-)

von (prx) A. K. (prx)


Lesenswert?

Eleganter ist
  (void) UDR;

von MeinerEiner (Gast)


Lesenswert?

Wars bei manchen Compilern nicht so, dass bei

a;

ne Warnung kommt von wegen "Statement with no effect"?

von Klaus W. (mfgkw)


Lesenswert?

Aber nur, wenn nicht volatile
:-)

von J. V. (janvi)


Lesenswert?

Wenn hier schon die GCC volatile Spezialisten zusammen sind, habe ich 
auch noch eine Frage dazu:

volatile int16_t variable

definiert eine Variable deren Inhalt als Integer mit Vorzeichen bewertet 
wird. Sodann übergebe ich diese Variable als Parameter per Reference in 
eine Funktion:

funktion (&variable);

Dortselbst schreibt diese irgendwas rein:

void funktion(int16_t* variable)
{ *variable = irgendwas;
  if ((int16_t) *variable - signedintegervariable) nochwas();
}

Nun kommt GCC mit einer unverständlichen Warnung von wegen "passing 
argument of funktion discards qualifiers from pointer target type" oder 
so ähnlich. Tatsächlich scheint GCC den Typ plötzlich komplett zu 
ignorieren und zwar inklusiv seiner signed Eigenschaft. Lässt man 
volatile weg, kommt keine Warnung und alles ist richtig.

Der Kampf geht aber weiter: Lässt man in der if Zeile den Typecast weg, 
so ist das Resultat (mit und ohne volatile) von signed int minus signed 
int nicht etwas ein signed int sondern ein unsigned int. Mit anderen 
Worten: Das if funktioniert nur mit typecast aber nicht ohne. Gleicher 
Effekt mit und ohne eigeschalteten Optimierer

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> Nun kommt GCC mit einer unverständlichen Warnung von wegen "passing
> argument of funktion discards qualifiers from pointer target type" oder
> so ähnlich.

Womit er recht hat, denn ein normaler Zeiger darf nicht auf eine 
"volatile" Variable zeigen, weil ebendiese besondere Eigenschaft dadurch 
verloren ginge. Andersrum ist jedoch zulässig.

Also: void funktion(volatile int16_t* variable)

Den Rest der Frage habe ich nicht verstanden, denn das ob das Ergebnis 
einer Subtraktion 0 ist hängt heutzutage nicht von der 
Vorzeicheneigenschaft der Rechnung ab.

von Falk B. (falk)


Lesenswert?

@  Karl heinz Buchegger (kbuchegg) (Moderator)

>Sicher. Das ist eine Expression wie jede andere auch.

Eine was????

Du meinst einen logischen AUSDRUCK!!!

Nieder mit dem DENGLISCH!!!

MFG
Falk

von J. V. (janvi)


Lesenswert?

Tatsächlich funktioniert es korrekt, wenn man volatile an beiden Stellen 
hinschreibt.

Im zweiten Teil soll es korrekt heissen:

if ((int16_t) (*variable - signedintegervariable) > 0 ) nochwas();

also wenn die Zahl positiv ist. Hier mal der Originalcode daß ich nicht 
nochwas vergesse, wo ich mir für den Systick (von meinem STM32 
Lieblingsteil) einen Timer gebastelt habe weil ich es nicht sehen kann, 
daß STM es in den Beispielen immer so macht wie man es nicht sollte. 
(nämlich in einer Loop die Zeit zu verbraten)
1
void SetFlop(int16_t* timer, int16_t length)
2
{
3
  *timer = (tictac + length);
4
}
5
6
int TestFlop(int16_t* timer)
7
{
8
 if ((int16_t)(tictac - *timer) > 0) return (TRUE); 
9
 else return (FALSE);
10
}

Die Nutzung sieht dann so aus:

1
void mz0(void)
2
{ SetFlop (&MaTimer,2000);  // Timer starten
3
  MaZust = 1;
4
}
5
6
void mz1(void)
7
{if (TestFlop(&MaTimer))  MaZust = 2;}
8
9
void mz2(void)
10
{...usw 
11
12
void StateMachine()
13
{switch (MaZust)    // Berechneter Sprung mit Zustandsmerker
14
  {case 0:  mz0(); break;
15
   case 1:  mz1(); break;
16
   case 2:  mz2(); break;  //usw.
17
  }
18
}

Mit dem Typecast funzt alles Wunderbar, ohne Typecast aber nicht im 
negativen Bereich des tictac Systick. tictac ist selbstverständlich 
wegen Schreibvorgang im Systick Interrupt auch volatile int16_t. Scheint 
dann aber kein volatile Problem zu sein sondern ich hab was anderes 
übersehen?

von J. V. (janvi)


Lesenswert?

der Fehler lag bei

extern volatile int32_t tictac;

und mit

extern volatile int16_t tictac;

ist alles gleichzeitig richtig und es funzt prima auch ohne typecast.
Also nichts mit volatile zu tun wie ich wegen der Warnung vermutete.
Manchmal hilft es schon, wenn man nur irgenjemand was vorjammern kann.

von (prx) A. K. (prx)


Lesenswert?

Dass auf einer 32-Bit Maschine und
  int16_t a, b;
zwischen
  (a - b)              [1]
und
  (int16_t)(a - b)     [2]
ein Unterschied besteht, das sollte hoffentlich klar sein. Nämlich 
beispielsweise bei a=30000 und b=-20000. Denn dann ist [1] 50000, und 
[2] -15536.

Neben dem Jammern hätte auch die Information geholfen, dass von einer 32 
Bit-Maschine die Rede ist. Das ging aus dem ursprünglichen Posting nicht 
hervor.

von J. V. (janvi)


Lesenswert?

> das sollte hoffentlich klar sein.

ääh warum das nun ?

int16_t minus int16_t sollte doch doch unabhängig von einem 32 bit 
System immer in16_t geben?

Wenn ich natürlich int32_t minus int16_t rechne kommt int32_t raus wo 
das Vorzeichenbit dann etwas weiter links liegt was mit dem 
unfreiwilligen und unnötigen Typecast wieder zurückgebogen wurde

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> int16_t minus int16_t sollte doch doch unabhängig von einem 32 bit
> System immer in16_t geben?

Keineswegs. Ein Blick in ein C Handbuch sollte dir das verdeutlichen. 
Auf Neudeutsch unter "integer promotion rules" zu finden.

Kurzfassung: Alles kleiner als "int" wird zu "int" erweitert und erst 
dann wird gerechnet.

von J. V. (janvi)


Lesenswert?

> Auf Neudeutsch unter "integer promotion rules" zu finden.

hm - war mir bislang nicht wirklich klar da signed normal nie gebraucht 
und unsigned wohl der Default Fall bei GCC und auch anderen Compilern 
scheint.

In meinem C Büchlein heist es tatsächlich (im noch nie gelesenen) 
Anhang:

Pointer Arithmetik und Vergleiche sind im allgemeinen nicht portabel. 
Verwendet man eine cast Konstruktion, ist die Portabilität 
gewährleistet. Pointer Vergleiche werden auf einigen Systemen als 
signed, auf anderen als unsigned Vergleiche vorgenommen.

Zu was schreibt man den Typ dann noch hin wenn der Compiler doch macht 
was er will?

von Mark B. (markbrandis)


Lesenswert?

Krishna schrieb:
>>könnte da sogar reichen...
> wäre aber was für einen obscated c contest

Den gibt es aber eh nicht mehr (den International Obfuscated C Code 
Contest), oder? Ich meine sie haben es bis heute nicht geschafft, die 
Sourcecodes von 2006 zu veröffentlichen. Geschweige denn dass es eine 
neue Runde gäbe.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> hm - war mir bislang nicht wirklich klar da signed normal nie gebraucht
> und unsigned wohl der Default Fall bei GCC und auch anderen Compilern
> scheint.

Unsigned ist nie der implizite Normalfall, ausser auf manchen 
Maschinen als "char".

> Pointer Arithmetik und Vergleiche sind im allgemeinen nicht portabel.
> Verwendet man eine cast Konstruktion, ist die Portabilität
> gewährleistet. Pointer Vergleiche werden auf einigen Systemen als
> signed, auf anderen als unsigned Vergleiche vorgenommen.

Halte ich in dieser Formulierung für Quark, es sei denn es werden damit 
Compiler eingeschlossen, die es mit dem Standard nicht allzu genau 
nehmen. Ausserdem sind die erwähten Vergleiche garantiert nur Vergleiche 
von Pointern, nicht von Integern, also als "Pointer-Arithmetik und 
Pointer-Vergleiche" zu lesen.

Der C Standard definiert, dass die Differenz zweier Adressen vom 
gleichen Objekt (also meist Array) als ptrdiff_t ausgedrückt werden 
kann, und dass (logischerweise) dieser Typ ein Vorzeichen hat. Es bleibt 
aber offen, ob dieser Typ int oder long entspricht.

Plattformen mit ptrdiff_t=long sind beispielsweise 64-Bit PCs, die aus 
historischen Gründen trotzdem mit 32-Bit int aber 64-Bit Adressen 
arbeiten. Da wird es etwas haarig.

Wenn auf einer 16-Bit Maschine wie üblich ptrdiff_t=int gilt, dann kann 
kein Array-Objekt grösser werden als 32767 Bytes, weil sonst diese 
Bedingung verletzt wäre (trivial für char-Arrays, gilt das jedoch auch 
für andere Arrays).

Ob ein Vergleich zweier vergleichbarer (*) Pointer mit oder ohne 
Vorzeichen stattfindet ist für Portabilität belanglos und tatsächlich 
von der Maschine abhängig, wenngleich vorzeichenbehaftete Adressräume 
selten sind (mir sind nur die Transputer bekannt). Entscheidend ist 
jedoch, dass eine berechnete Differenz vorzeichenbehaftet sein muss.

*: Nicht portabel weil völlig undefiniert sind allerdings Vergleiche von 
Adressen verschiedener Objekte.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> Zu was schreibt man den Typ dann noch hin wenn der Compiler doch macht
> was er will?

Das Verhalten ist ziemlich gut definiert und der Compiler tut das was er 
soll. Vorsicht mit solchen Vorwürfen, wenn man erkennbar grosse Lücken 
im Verständnis von C hat.

Von dem Tipp mit eifrigem Einsatz von Casts kann ich nur dringendst 
abraten. Ein Cast ist eine Brechstange, die vieles von dem aushebelt, 
was der Compiler an Überprüfungen durchführt und sollte so selten wie 
möglich eingesetzt werden. Und wenn, dann sollte man genau wissen was 
man tut, nicht raten.

von Klaus W. (mfgkw)


Lesenswert?

Vielleicht ist das Buch 1980 oder so; die Formulierung
ist so wie sie dasteht wirklich Quark.

Wenn Pointerarithmetik per se unbrauchbar wäre, müsste ich meine
ganzen letzten Jahre nochmal neu machen.

von J. V. (janvi)


Lesenswert?

>Vielleicht ist das Buch 1980 oder so; die Formulierung
>ist so wie sie dasteht wirklich Quark.

es ist von 1987 (1. Auflage Sybex) und dort habe ich es wieder in den 
Schrank gestellt weil C auf einem 8085 unbrauchbar war. Vielleicht 
sollte ich mir doch mal ein neues Büchlein kaufen denn C89 und C99 und 
so sind da dran auch vorbeigegangen.

>Von dem Tipp mit eifrigem Einsatz von Casts kann ich nur dringendst
>abraten. Ein Cast ist eine Brechstange, die vieles von dem aushebelt,

Wenn ich es nun korrekt verstanden habe, ist an dieser Stelle aber auch 
dann ein Cast zu empfehlen obwohl es auch ohne funktioniert weil nicht 
garantiert ist, daß ein nicht explizit einer typbehafteten Variablen 
zugewiesenes Resultat nicht gleich dem der beiden Operanden sein muß.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> Wenn ich es nun korrekt verstanden habe, ist an dieser Stelle aber auch
> dann ein Cast zu empfehlen obwohl es auch ohne funktioniert weil nicht
> garantiert ist, daß ein nicht explizit einer typbehafteten Variablen
> zugewiesenes Resultat nicht gleich dem der beiden Operanden sein muß.

Könntest du diesen Satz mal in ein Beispiel giessen? Der Code oben 
eignet sich eher weniger, weil 16-Bit Timer nicht wirklich oft mit 
Vorzeichen interpretiert werden und weil das Verhalten von Überlauf bei 
vorzeichenbehafteter Rechnung nicht definiert ist.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> es ist von 1987 (1. Auflage Sybex) und dort habe ich es wieder in den
> Schrank gestellt weil C auf einem 8085 unbrauchbar war.

Das erklärt die Aussage. Die erwähnten integer promotion rules gibt es 
in ihrer heutigen Form erst seit ANSI-C, aka C89.

Davor, also in K&R-C, war nicht klar definiert, ob beispielsweise die 
Differenz zwischen 16-bit signed und 8-bit unsigned nun signed oder 
unsigned ist. Der eine Compiler war value-preserving wie C89, der andere 
unsigned-preserving und mindestens einer konnte vorsorglich beides.

Insofern konnte es damals tatsächlich vorkommen, dass die Differenz
   (int)10 - (unsigned char)20
bei einem Compiler negativ war, beim anderen positiv.

Aber das Thema ist seit C89 durch.

von Gast (Gast)


Lesenswert?

Dass es immer noch Leute gibt, die sagen dass 'volatile' bedeutet, dass 
keine Optimierungen auf die Variable angewendet werden darf!

von (prx) A. K. (prx)


Lesenswert?

Gast schrieb:

> Dass es immer noch Leute gibt, die sagen dass 'volatile' bedeutet, dass
> keine Optimierungen auf die Variable angewendet werden darf!

Was willst du damit sagen? Vor allem: wem?

von Simon K. (simon) Benutzerseite


Lesenswert?

Gast schrieb:
> Dass es immer noch Leute gibt, die sagen dass 'volatile' bedeutet, dass
> keine Optimierungen auf die Variable angewendet werden darf!

Ja, ist echt unfassbar, dass es heutzutage noch Leute gibt, die die 
Wahrheit erzählen.

von J. V. (janvi)


Lesenswert?

>Könntest du diesen Satz mal in ein Beispiel giessen? Der Code oben
>eignet sich eher weniger, weil 16-Bit Timer nicht wirklich oft mit
>Vorzeichen interpretiert werden und weil das Verhalten von Überlauf bei
>vorzeichenbehafteter Rechnung nicht definiert ist.

Das obenstehende Beispiel zeigt den Cast in der Testflop Funktion.
Ein anderes Beispiel habe ich moentan nicht.

Die vozeichenbehafteten (Software-Timer) gibt es schon immer und ich 
glaube, alle Echtzeit Betriebssysteme machen das auch so. Früher halt in 
Assembler wo es dazu einen Half-Carry bzw. Rotieren ins Carry gab. Das 
Einzige was im Beispiel noch fehlt ist die ISR für den SYSTICK und der 
besteht aus tictac++; Falls es noch unklar ist wie es geht:

SetFlop startet eine Zeit
TestFlop prüft ob die Zeit abgelaufen ist

Das ist schon alles und verblüffend einfach. Der immense Vorteil 
gegenüber allen anderen Methoden ist, daß auch ohne Multitask beliebig 
viele Zeiten (nur begrenzt durch das RAM) gleichzeitig laufen können. 
Und zwar ohne daß hierbei Rechenzeit mit dekrementieren oder 
inkrementieren von ebenso vielen Zeiten verbraten wird. Einzige 
Einschränkung: Bei einem 16 bit Timer ist die längste Zeit 15 bit und 
bei einem 32 bit Timer ist die längste Zeit 31 bit usw. 
Zustandsmaschinen können dabei ebensoviele gleichzeitig laufen wie 
Timer. Die maximale Zykluszeit addiert sich hier als Unschärfe oder 
Jitter zur Timerzeit. Also eher ein Aufbau für "sichtbare" längere 
Zeiten, so ab 10-100 mSec aufwärts.

>und weil das Verhalten von Überlauf bei
>vorzeichenbehafteter Rechnung nicht definiert ist.

Das ist sehr wohl definiert und nachzulesen beim Zweierkomplement.
Möglicherweise gibt es irgendwelche DSPs mit Sättigungsarithmetik aber 
das ist dann auch separat dokumentiert und beim STM32 definitiv nicht 
so.

Deshalb reicht das Abfragen eines abgelaufenen Timers spätestens nach 
einer maximalen Timer Zeit vorzunehmen, um den Überlauf nicht zu 
verpassen. Wenn die Zykluszeit hierzu nicht taugt, hat man sowieso was 
anderes falsch gemacht. Tut beliebig oft, rund um die Uhr, ohne 
volatile, Multitask und in allen Bitbreiten. Diese habe ich 
zwischenzeitlich entsprechend dem Zielsystem auf mir bislang unhandlich 
erscheinende 32 bit Zahlen umgestellt.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> Das ist sehr wohl definiert und nachzulesen beim Zweierkomplement.

Nur dass C keine Zweierkomplement-Arithmetik impliziert und 
Sättigungs-Arithmetik oder Overflow-Traps durchaus zulässig sind. Nur 
bei vorzeichenloser Arithmetik ist in C das Modulo-Verhalten definiert.

> Möglicherweise gibt es irgendwelche DSPs mit Sättigungsarithmetik aber
> das ist dann auch separat dokumentiert und beim STM32 definitiv nicht
> so.

Ich unterscheide zwischem Implementierung und Definition. Also: Das 
Verhalen ist nicht definiert, aber im Fall der STM32-Implementierung 
ziemlich bekannt.

Aber zur vorsorglichen Abschreckung ein Beispiel, wie man sich auch in 
solchem Kontext verrechnen kann: Wenn eine Maschine nur in halber Breite 
multiplizieren kann und eine Multiplikation relativ teuer ist, dann muss 
der Code nur 2 der maximal 3 Teilprodukte rechnen, denn wenn beide 
mittleren Teilprodukte relevant sind, dann gibt es Überlauf und das 
Ergebnis ist formal undefiniert. Es kann also sein, dass eine so 
optimierte Multiplikation keine Modulo-Rechnung mehr ist.

Ähnliche Überraschungen sind auch über den Optimizer denkbar. Ein von 
der Erwartung abweichendes Verhalten, dass nur bei Überlauf eintritt, 
muss er nicht einkalkulieren.

von (prx) A. K. (prx)


Lesenswert?

J. V. schrieb:

> SetFlop startet eine Zeit
> TestFlop prüft ob die Zeit abgelaufen ist

In diesem Zusammenhang ist ein Cast durchaus sinnvoll. Wobei sich mir 
aber die Frage stellt, ob es wirklich sinnvoll ist, solche Timer 
unterhalb von "int" anzusiedeln. Und ab "int" tritt das Problem nicht 
mehr auf.

Bei RISCs darf man davon ausgehen, dass kleinere Daten zwar im RAM Platz 
sparen, aber tendentiell zusätzlichen Code kosten. Bei lokalen Daten und 
Parametern (also Registern) ist dieser Effekt besonders stark 
ausgeprägt.

von J. V. (janvi)


Lesenswert?

>Nur bei vorzeichenloser Arithmetik ist in C das Modulo-Verhalten definiert.

Auch noch das! Müsste aber genauso gehen, warum auch komplizierter? 
Werds bei Gelegenheit auf uint32_t umstellen und mit einer Maske auf bit 
31 so tun als ob ich das Vorzeichen abfrage. Womit sich die bisherige 
Tradition wieder bestätigt hat, von signed möglichst nicht nur bei char 
die Finger wegzulassen.

von (prx) A. K. (prx)


Lesenswert?

Nicht gleich die Flinte ins Korn werfen, deine Variante funktioniert de 
fakto durchaus. Wobei ich allerdings die Timer als "unsigned" laufen 
lassen würde, um erst die Differenz nach "int" zu casten. In bekannter 
Umgebung brennt da aber in beiden Varianten nichts an.

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.