Krautkanal.com

Veröffentlicht am 2016-05-11 19:01:06 in /prog/

/prog/ 8800: C

to_soham Avatar
to_soham:#8800


unsigned char x = 0xFF;
if (~x) {
  printf("1\n");
} else {
  printf("0\n");
}


1 oder 0, Bernd.
Ohne auszuprobieren jetzt!

tereshenkov Avatar
tereshenkov:#8801

Kompiliert nicht.

aleclarsoniv Avatar
aleclarsoniv:#8802

>>8800
1.
'x' wird zu int promoted und die oberen Bits bleiben 0, da 0xFF in jedem Fall in einem (signed) int darstellbar ist. Nach dem Komplement sind die oberen Bits alle 1. Das 'if' schlägt bei jedem (int-) Wert außer 0 an.

p_kosov Avatar
p_kosov:#8803

>>8802
Sollte nicht erst die Negierung erfolgen und dann das auswerten des ifs?

urbanjahvier Avatar
urbanjahvier:#8805

Du kannst es ja wieder nach x schreiben. Dann wird es in ein tschar verkästnert.


































Nur leider steht nirgendwo geschrieben, daß ein Char 8 bits hat. TILT

C-Standard ist scheisse scheisse scheisse scheisse scheisse.

jitachi Avatar
jitachi:#8806

Gott wie war das schön mit assembler.

NEG ; oder zur Not XOR 255
JZ fettich

andyisonline Avatar
andyisonline:#8807


unsigned char x = 0xFF; // x = 255
if (~x) {              // false, da x = 255 = true => ~x = false
  printf("1\n");        // wird nicht ausgeführt, da ~x = false
} else {
  printf("0\n");        // '0' wird ausgegeben
}


PENIS

>>8805
>Nur leider steht nirgendwo geschrieben, daß ein Char 8 bits hat.
Doch, steht es du megahurrenson

Siehe
http://flash-gordon.me.uk/ansi.c.txt
Section 2.2.1 - Character sets und 2.2.4.2 - Numerical limits

joe_black Avatar
joe_black:#8808

>>8807
*mindestens 8 bit

wahidanggara Avatar
wahidanggara:#8809

Lerne erstmal was default int promoschen is

iamglimy Avatar
iamglimy:#8810

>>8809
Hat aber nichts mit dem Beispiel zu tun

snowwrite Avatar
snowwrite:#8812

Danke OP. Der Faden hat mich mal wieder daran erinnert warum ich C so scheiße finde.

puzik Avatar
puzik:#8813

>>8812
>Danke OP. Der Faden hat mich mal wieder daran erinnert warum ich C so scheiße finde.

Das wollte ich erreichen :3

Und so?

char x = 0xFF;
if (~x) {
  printf("1\n");
} else {
  printf("0\n");
}

Naja. Mal sehen, was so geantwortet wird.

langate Avatar
langate:#8814

>>8812
Wieso kannst du es nicht?

aluisio_azevedo Avatar
aluisio_azevedo:#8815

>>8813

char darf auch unsigned sein.
Wenn es signed ist könnte es passieren dass -1 rauskommt was dann durch die int promotion auf 2^n-1 aufgeblasen wird und dessen Komplement kann 0 sein.

Es ist aber rationeller, sich mit einem stumpfen Messer aus NaCl zu schächten, das tut nicht so weh.

joshhemsley Avatar
joshhemsley:#8816

>>8803
Habe ich ja gesagt. 'Komplement' ist bitweises negieren.
>>8805
Ein 'unsigned char' deckt IMMER wenigstens den Bereich 0 bis einschließlich 255 ab ($2.2.4.2).

Hier nochmal Schritt für Schritt was passiert:
[code]unsigned char x = 0xFF;[/code]
'0xFF' ist eine Konstante vom Typ int. Bei der Zuweisung wird int zu unsigned char umgewandelt. Da 0xFF von unsigned char dargestellt werden kann, wird der Wert nicht geändert ($3.2.1.2). 'x' enthält also wie erwartet 0xFF.
[code]if (~x)[/code]
Zuerst wird 'x' zu int promoted (für die expression), da es in einem int dargestellt werden kann (ansonsten müsste es möglicherweise zu unsigned int umgewandelt werden, $3.2.1.1). Die Bits oberhalb von 0xFF werden mit 0 aufgefüllt. Mindestens 8 Bits (int ist mindestens 16 Bit groß) sind nun also 0.
Der Zwischenwert (vom Typ int) wird nun negiert. 0xFF wird zu 0x00. Die Bits oberhalb davon werden aber nun alle 1.
Da für 'if' jede Bedingung wahr ist, die nicht 0 ist ($3.6.4.1), wird der erste Block ausgeführt.

Nach diesem Muster werden arithmetischen Operationen immer mit unsigned oder signed int durchgeführt. Man benötigt also meistens nur eine Ausführungseinheit für jeden Operator in der CPU und nicht für jeden Typ von unterschiedlicher Größe eine eigene (z.B. meistens nur zwei ADD-Befehle für jeweils signed/unsigned, aber nicht für char, short, long, long long, etc). Außerdem geht man von einer Art Load-Store-Maschine aus: Typumwandlungen fallen normalerweise beim Laden ins Register (RAM->CPU) oder Entladen in den Speicher (CPU->RAM) an.

Und die Referenz: http://port70.net/~nsz/c/c89/c89-draft.html

lisakey1986 Avatar
lisakey1986:#8824

Bernd ist vor kurzem auch über diesen Fehler gestolpert und lernte dann von Integer-Promotion.

VinThomas Avatar
VinThomas:#8844

Kann es wirklich passieren, dass Variablen in einem Ausdruck promotet werden, bevor der Ausdruck vollständig ausgewertet ist?

Das scheint auf mich sehr gefährlich und unberechenbar. Das muss doch spezifiziert sein, oder Bernd?

jamesmbickerton Avatar
jamesmbickerton:#8848

Natürlich. Was glaubst du worüber wir hier die ganze Zeit reden?? Default int Promotion.

Weil Dennis' VAXkrebsmaschine damals Integer Register hatte und dann eben damit gerechnet wurde.

Genauso hatten die irgendwelche Memory walk instruktionen, Store Register in [Adressregister++]. Also gibt es ++ und -- und auch speziell für Pointer.

Son Quatsch wie Carry auswerten hingegen braucht Dennis nicht. Kannste bei Fefe nachlesen wie man sich einen abwürgen muß um einen Überlauf zu detektieren.

meisso_jarno Avatar
meisso_jarno:#8849

>>8844
>Kann es wirklich passieren, dass Variablen in einem Ausdruck promotet werden, bevor der Ausdruck vollständig ausgewertet ist?

Ja darum gehts doch hier.

>Das scheint auf mich sehr gefährlich

Es ist gefährlich, wenn man es nicht kennt.

> und unberechenbar.



>Das muss doch spezifiziert sein, oder Bernd?

Natürlich ist es das.

mattsapii Avatar
mattsapii:#8850

So und jetzt für die, die aufgepasst haben und noch mehr über C wissen:


#include <stdio.h>
int main(void)
{
  int a = -1;
  unsigned b = 1;
  signed char c = -1;
  unsigned char d = 1;

  if (a < b)
    printf("Fefe ist ");
  else
    printf("Op ist ");
  if (c < d)
    printf("absolut genial.\n");
  else
    printf("ein totaler Volltrottel.\n");
}


Was wird ausgegeben? Bonuspunkte für Antwort ohne Ausprobieren. alsob.jpg ich das nachprüfen könnte.

gojeanyn Avatar
gojeanyn:#8851

Wo soll da der Trick sein? C kann doch nicht so ungeheuer Scheisse sein, daß es ein signed in einen unsigned konvertiert?

ninjad3m0 Avatar
ninjad3m0:#8852

>>8851
>Wo soll da der Trick sein?

Es gibt keinen Trick.
Aber stimmt die tatsächliche Ausgabe mit deiner erwarteten Ausgabe überein? Probiers mal aus.
Wenn das raus kommt, was du erwartet hast, dann hast du mindestens 2 nicht ganz intuitive C-Regeln verstanden. integer promotion und type balancing.

kazukichi_0914 Avatar
kazukichi_0914:#8853

fefe.c: In function ‘main’:
fefe.c:9:9: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
  if (a < b)
        ^
fefe.c:17:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^


"Op ist absolut genial." würde ich ausschließen.

stayuber Avatar
stayuber:#8855

>>8853
>"Op ist absolut genial." würde ich ausschließen.

:3
Was an diesem Code ist denn nicht C99-konform?

BrianPurkiss Avatar
BrianPurkiss:#8857

>>8850

% cat fefe.c
#include <stdio.h>
#include <stdint.h>

#define cmp32ui(a,b) (-cmp32iu(b,a))

static inline int
cmp32iu(int32_t a, uint32_t b)
{
  return ((a < 0) ? (-1) : ((a > b) - (a < b)));
}

int
main(void)
{
  int32_t a = -1;
  uint32_t b = 1;
  int8_t c = -1;
  uint8_t d = 1;

  if (cmp32iu(a, b) < 0)
    printf("Fefe ist ");
  else
    printf("Op ist ");
  if (c < d)
    printf("absolut genial.\n");
  else
    printf("ein totaler Volltrottel.\n");
  return (0);
}

% clang fefe.c -o fefe
% ./fefe
Fefe ist absolut genial.
%


FUGG :DD

Neuste Fäden in diesem Brett: