Forum: Mikrocontroller und Digitale Elektronik Rätselspass für die Pros


von Gastinio/Linda (Gast)


Lesenswert?

Hallo zusammen,

Wer mal keine Lust auf Sudoku oder so hat, kann sich ja mal an dem 
C-Rätsel probieren.

Was macht die folgende Funktion?

int getmessage (int c)
{
  return (!(c&~3))["(c&3)"]&c&3;
}

Mit freundlichen Grüssen

Gastino/Linda

von SuperUser (Gast)


Lesenswert?

Lösung:
Der Programmier wurde entlassen....

von Gastinio/Linda (Gast)


Lesenswert?

setze mal für c 10 ein.... was kommt raus?

von malle? (Gast)


Lesenswert?

nix? null? nada?

von uCler (Gast)


Lesenswert?

Wieso - ne 3 mit ner Klammer verunden hat schon was...

von Andy (Gast)


Lesenswert?

Da kommt Kässekuchen raus, mmmmhhhh, könnt ihr das richen. Und dann 
kommt die Sonne raus an einem schönen Frühlingmorgen nach einer 
wollkigen Woche, die Luft ist do rein und es richt nach Blütten in den 
Bäumen......die Vögel zwitschern und frisches Kod ist auf dem 
Bürgersteig...... come on be serious!!!!!!!

von Gastinio/Linda (Gast)


Lesenswert?

bitte unötige kommentare zurückhalten...

von Karl H. (kbuchegg)


Lesenswert?

> int getmessage (int c)
> {
>   return (!(c&~3))["(c&3)"]&c&3;
> }
>
> setze mal für c 10 ein.... was kommt raus?

Für den ersten Teil switche ich mal zu binär


   3                 00000011
  ~3                 11111100

   c    (10)         00001010

   c&~3              00001000  also 8

 !(c&~3)     da c&~3 ungleich 0 ist, macht der ! eine satte 0
             daraus

  0["(c&3)"]  ergitb daher '(', 0x28, also  00101000

  00101000 & c        00101000
                      00001010
                     ---------
                      00001000

  & 3                 00000011
                     ---------
                      00000000

Wenn ich mich zwischendurch nicht verhaut habe, dann kommt
da also 0 raus.

Was das ganze allerdings sein soll, kann ich nicht erraten.

von ChrisV (Gast)


Lesenswert?

dachte sich der Programmierer obiger Funktion wohl auch

von Carsten P. (papa_of_t)


Lesenswert?

Was diese Funktion macht? Sie zeigt uns wie man unverständlich 
programmiert (durch Weglassen von erklärenden Kommentaren), und daß das 
"C" als Sprachenname für "cryptic" steht .. :-)

von Karl H. (kbuchegg)


Lesenswert?

Carsten Pietsch wrote:
> Was diese Funktion macht? Sie zeigt uns wie man unverständlich
> programmiert (durch Weglassen von erklärenden Kommentaren), und daß das
> "C" als Sprachenname für "cryptic" steht .. :-)

Ich tendier eher dazu, dass hier jemand absichtlich möglichst
kryptisch sein wollte um irgendetwas zu demonstrieren.
Wahrscheinlich ist das Bsp. extra für die Frage hergestellt
worden.

Irgendeinen tieferen Sinn kann ich immer noch nicht erkennen.
Soviel steht aber fest: Die Funktion kann nur Werte im
Bereich 0 bis 3 (inklusive) liefern.

von Gastinio/Linda (Gast)


Lesenswert?

Diese Aufgabe hat nicht viel mit Programmieren zu tun. Ist eine Aufgabe 
aus der letzten CE Programmieren 1 Klausur...

von Dennis (Gast)


Lesenswert?

Vielleicht ne Hausaufgabe...

von Tassilo B. (big_t)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

Gastinio/Linda wrote:
> Diese Aufgabe hat nicht viel mit Programmieren zu tun. Ist eine Aufgabe
> aus der letzten CE Programmieren 1 Klausur...

Dann gehts also eher darum, das Ding zu analysieren.
Also: Wie liege ich?


von Carsten P. (papa_of_t)


Lesenswert?

Karl-Heinz, frag nicht so unproduktiv zurück .. :-)

Linda hätte gerne ihre Hausaufgabe von Dir erledigt..

von Gastinio/Linda (Gast)


Lesenswert?

1A..... :-)

von Karl H. (kbuchegg)


Lesenswert?

Aber jetzt hab ich mal für dich ein Rätsel:

In einem Ort werden Temperaturen gemessen. Obwohl die
Temperaturen alle in einem vernünftigem Bereich liegen
ist der errechnete Durchschnittswert ungewöhnlich hoch:
1
#include <stdio.h>
2
3
const int march[31] = {
4
        8, 5, 7, 2, -4, -14,  -7, -4, -2,  0,
5
        0, 2, 5, 7,  2,  -4, -14, -7, -4, -2,
6
        1, 7, 2, 2, -2,  -3,  -4,  6, -4,  3, 9 };
7
8
int main()
9
{
10
  unsigned i, count = 31;
11
  int sum = 0;
12
13
  for( i = 0; i < count; i++ )
14
  {
15
    sum += march[ i ];
16
  }
17
  printf( "The average low temperature in March was"
18
          " %d degrees\n", sum / count );
19
  return 0;
20
}

Was geht hier vor?

von Rahul, der Trollige (Gast)


Lesenswert?

*höhö...
Da ist ein Fehler drin!

von Rahul, der Trollige (Gast)


Lesenswert?

nee, doch nicht

von PeakRunner (Gast)


Lesenswert?

wohl nicht wirklich ein Fehler,
aber in der printf-Zeile würde ich was ändern ...

von Markus (Gast)


Lesenswert?

@PeakRunner:
Da kommt ziemlich Unsinn raus, das würde ich schon einen schweren Fehler 
nennen.

Mit float wäre das nicht passiert... ;)

Markus

von PeakRunner (Gast)


Lesenswert?

Naja, wie man es sieht,
die Rechnung an sich ist ja richtig, die Frage ist ja nur mit was man 
rechnet ...

von ChrisV (Gast)


Lesenswert?

Welcher März hat denn 31 Tage???

von PeakRunner (Gast)


Lesenswert?

Jeder ...

von ChrisV (Gast)


Lesenswert?

Arrghh wie peinlich (rotwerd)

von Karl H. (kbuchegg)


Lesenswert?

PeakRunner wrote:
> wohl nicht wirklich ein Fehler,
> aber in der printf-Zeile würde ich was ändern ...

Was würdest du ändern?

von PeakRunner (Gast)


Lesenswert?

1
 printf( "The average low temperature in March was"
2
          " %f degrees\n", (float) sum / count );

von Karl H. (kbuchegg)


Lesenswert?

PeakRunner wrote:
>
1
>  printf( "The average low temperature in March was"
2
>           " %f degrees\n", (float) sum / count );
3
>

Wäre ne Möglichkeit.
Aber nimm mal an, ich gestehe dir kein float zu.
Was ist das Problem im ursprünglichen Code?

von ich&er (Gast)


Lesenswert?

irgendein "überlauf"-problem vielleicht?

von Martin K. (mkohler)


Lesenswert?

> Welcher März hat denn 31 Tage???
derjenige, der genau so viele Nächte hat, so ziemlich jeder.

Zum Rätsel: Man muss halt die Zeichen - äähh Vor-Zeichen der Zeit resp. 
Zahl im Auge behalten, sonst gehen einem die Augen oder Zahlenbereiche 
über...

von Karl H. (kbuchegg)


Lesenswert?

Martin hats.

von Rahul, der Trollige (Gast)


Lesenswert?

Da hatte ich ja doch Recht (mit dem Fehler...).

>Aber nimm mal an, ich gestehe dir kein float zu.
>Was ist das Problem im ursprünglichen Code?

Fixpunktarithmetik dürfte helfen...

von Karl H. (kbuchegg)


Lesenswert?

Rahul, der Trollige wrote:
> Da hatte ich ja doch Recht (mit dem Fehler...).
>
>>Aber nimm mal an, ich gestehe dir kein float zu.
>>Was ist das Problem im ursprünglichen Code?
>
> Fixpunktarithmetik dürfte helfen...

Auf meinem System lautet die Ausgabe, dass der Druchschnitt
138547331 Grad betragen würde.
Globale Erwärmung scheidet ebenfalls aus.



von Falk (Gast)


Lesenswert?

Ich seh keinen Fehler, wen man mal von der INT Division sum / count 
absieht.

MFG
Falk

von ich&er (Gast)


Lesenswert?

das vorzeichenbit bei unsigned/signed muss beachtet werden...

von Karoly Kovacs (Gast)


Lesenswert?

Es gibt zwei Möglichkeiten:

1. signed int count;
Dann bekommt man 0 Grad.

2. (wie früher bereits geschrieben) "float sum".

Karoly

von PeakRunner (Gast)


Lesenswert?

Das unsigned count würd ich ändern ...

von Karl H. (kbuchegg)


Lesenswert?

Der Fehler liegt hier

    sum / count

sum ist ein signed
count ist ein unsigned.

Gemäss dem Promotionsregeln werden signed Datentypen
zu unsigned promoted, bevor die Division duchgeführt
wird.
Da sum aber negativ ist, wird das zu einem riesengrossem
unsigned. Dividiert durch count bleibt die Zahl immer
noch extrem gross.

Das andere Problem ist, dass die Division als Ergebnis
einen unsigned Typ hat. %d ist aber nicht das richtige
Formatzeichen dafür. Rein formal wäre %u angemessen auch
wenn es das Problem nicht lösen würde.

mögliche Abhilfen
* count als signed ausführen.
* count vor der Division auf signed casten
  sum / (signed)count
  Dadurch würde allerdings der erhoffte Vorteil des
  unsigned Datentyps verloren gehen und ein neues
  Wurmloch eröffnet. Bringt also nicht viel.

Moral:
unsigned und signed Datentypen mischen kann zu höchst
unerwartetem Verhalten führen.

von Rolf Magnus (Gast)


Lesenswert?

Ich habe auch ein nettes C++-Rätsel, das sich aus persönlicher Erfahrung 
ergeben hat:
1
#include <fstream>
2
3
int main()
4
{
5
    std::ofstream("test.txt").flush() << "foobar\n";
6
}

Wozu dient der flush() in diesem Programm?

von mr.chip (Gast)


Lesenswert?

> return (!(c&~3))["(c&3)"]&c&3;

Verrät mir jemand, was es mit dieser ["(c & 3)"]-Syntax auf sich hat? 
:-)

von Rolf Magnus (Gast)


Lesenswert?

Ist ganz einfach. Der Index-Operator a[b] ist äquivalent zu *(a+b). Das 
beinhaltet auch, daß man a und b vertauschen kann.
"abc"[2] == 2["abc"] == 'b'

von Rolf Magnus (Gast)


Lesenswert?

Hrmpf... natürlich sehe ich es eine Zehntelsekunde nach dem Absenden. Es 
muß natürlich heißen: "abc"[2] == 2["abc"] == 'c'

von PeakRunner (Gast)


Lesenswert?

Ich schätz mal,
dass "foobar\n" direkt in die Datei test.txt geschrieben wird ...

von Karl H. (kbuchegg)


Lesenswert?

mr.chip wrote:
>> return (!(c&~3))["(c&3)"]&c&3;
>
> Verrät mir jemand, was es mit dieser ["(c & 3)"]-Syntax auf sich hat?
> :-)

Das ist ziemlich einfach, wenn man es weiss.

In C ist Arrayzugriff so definiert:
Die [] Zeichen sind 'syntactic sugar'. Sobald der Compiler
diese Zeichen sind, wandelt er das ganze um

   a[b]  <==>   *( a + b )

und da + kommutativ ist, kann man das auch schreiben als

   *( a + b ) <==> *( b + a )

und das wiederum ist equivalent zu

  *( b + a ) <==> b[a]

Ob du also
  int i[10];
  j = i[5];

oder

  int i[10];
  j = 5[i];

schreibst, ist in C eine reine Frage der Gewöhnung. Wir
sind halt an ersteres gewöhnt.

Intern macht der Compiler

  int i[10];

  j = *( i + 5);

Da i ein Array ist, reicht die blosse Erwähnung von i aus
um daraus einen Zeiger auf das erste Array Element zu machen.
In diesem Zusammenhang ist i also ein Pointer-Typ. Wie bei jeder
Pointerarithmetik wird der nicht Pointer-Typ (in diesem Fall i)
vor der Addition noch mit dem sizeof(*i) multipliziert. D.h.
da steht dann irgendwann in der Verarbeitungskette des Compilers.

  j = *(int)( (unsigned char*)i + 5 * sizeof(*i) );

Und das liefert dann tatsächlich das gewünschte: Beginnend ab
der Speicherposition i, 5 Elemente (wobei jedes in diesem Fall
ein int gross ist) weiterzählen, und den int von dort holen.

Diese a[i] <==> *(a+i)
Dualität ist im übrigen wichtig. Sie sorgt dafür, dass
Indexoperationen auch auf Pointer angewendet werden können:

   int * pI = malloc( 3 * sizeof(int) );
   ...
   j = pI[2];

Wieder
   pI[2] <==> *(pI + 2);

Anstatt dem Arraynamen i von vorher, steht jetzt bereits direkt
ein Pointer da. Ab da läuft dann alles weiter wie im Arrayfall.


Aber im Moment grüble ich noch über dern flush().
Rolf, gibst du einen Tip?

Wenn es so formuliert sein würde

    (std::ofstream("test.txt") << "foobar\n").flush();

hätte es wahrscheinlich irgendwas mit dem Buffering
zu tun und dem Umstand, dass da kein std::endl hinausgeschrieben
wird. Irgendwas in der Art.

Aber anders rum. Ich tappe im Dunkeln.


von Detlef _. (detlef_a)


Lesenswert?

bei The International Obfuscated C Code Contest gibts mehr von so Zeug: 
www.ioccc.org

Der '07 Contest geht 28. Feb. zu Ende, vielleicht wollt Ihr Euch daran 
ja beteiligen!?

das ist der 'best one liner' von 1994:
int 
_,O,__??('}'??);main(){while(O?gets((rand()%O++?':':_)+__)||puts(&__??(_ 
??))&_:srand(time((O+++_)))||O);}

Cheers
Detlef

von Karl H. (kbuchegg)


Lesenswert?

Die IOCCC ist nicht schlecht aber von wenig praktischem
Nutzen.

Wohingegen diese Rätsel hier
http://www.gimpel.com/html/bugs.htm
tatsächliche praktische Problemkreise aufzeigen.
(Und natürlich, wie das beworbene Produkt sie meldet)

(Da hab ich auch die signed/unsigned Falle her)

von Rolf Magnus (Gast)


Lesenswert?

@Karl Heinz

Ok, ein Tip: Es hat absolut nichts mit der eigentlichen Bedeutung der 
Funktion flush() oder irgendwelchen Buffers zu tun.

An alle, die nicht ausprobieren wollen, was das Programm mit und ohne 
Flush in die Datei schreibt:

mit flush() schreibt das Programm in die Datei:

    foobar

ohne das flush() (bei mir - der Wert kann verschieden sein):

    0x80487c1

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus wrote:
> @Karl Heinz
>
> Ok, ein Tip: Es hat absolut nichts mit der eigentlichen Bedeutung der
> Funktion flush() oder irgendwelchen Buffers zu tun.

Das hab ich befürchtet.

> ohne das flush() (bei mir - der Wert kann verschieden sein):
>     0x80487c1

Da ist doch noch ein Hinweis versteckt: Ich lese
da 'undefined behaviour' heraus.

Also weitersuchen.


von Karl H. (kbuchegg)


Lesenswert?

Warte mal.
Kann es sein, dass du den flush() nur deswegen hast, damit
da ein Sequence Point hineinkommt?

...

Ich zieh die Frage zurück. Der operator<< müsste eigentlich
als Sequence Point ausreichen.

von Karl H. (kbuchegg)


Lesenswert?

"I'm barking up the wrong tree"

Die Frage muss lauten:
Was kann den Compiler dazu bewegen, den falschen op<<
zu benutzen, sodass anstatt der Bytes die Adresse
des Strings geschrieben wird?
Und vor allen Dingen, wie kann flush() das beheben?

von Rolf Magnus (Gast)


Lesenswert?

Das geht schon mal in die richtige Richtung.

von Karl H. (kbuchegg)


Lesenswert?

Mein nächster Gedankengang:

Der Unterschied zwischen "mit flush" und "ohne flush"
besteht darin, dass das eine mal ein ostream Objekt
beteiligt ist, während es im anderen Fall ein ofstream
Objekt ist. ofstream erbt ja den flush() von ostream.

Hmm. Ich denke dass hat jetzt irgendwas mit dem
Function-Lookup zu tun.

ofstream hat selbst keinen op<<
Es erbt allerdings einen
ostream& ostream::operator<< (void*& val );
von ostream.
Auf der anderen Seite gibt es einen globalen
ostream& operator<< (ostream& out, const char* s );

Ich denke mal, dass der Compiler, solange es sich
um ein ofstream Objekt handelt, die globale Funktion
nicht benutzt, da es sich ja um ein ofstream Objekt
und nicht um ein ostream Objekt handelt. Es kommt
als der von ostream inheritated member op<< zum Zug.

Sorgst du aber dafür, dass aus dem ofstream ein ostream
wird, dann passt der Argumenttyp der globalen Funktion
perfekt und der Compiler nimmt den.


So mal 'aus dem Ärmel geschüttelt' und etwas konfus
niedergeschrieben. Sicher bin ich mir nicht.

von Rolf Magnus (Gast)


Lesenswert?

Hihi, da bin ich aber stolz, daß ich es geschafft habe, dich mit einer 
Programmierfrage so aus dem Tritt gebracht zu haben.

Du bist schon recht weit gekommen, aber driftest in die falsche 
Richtung.  Du wirst doch nicht vor dem Zielenlauf schlapp machen wollen? 
;-)

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus wrote:
> Hihi, da bin ich aber stolz, daß ich es geschafft habe, dich mit einer
> Programmierfrage so aus dem Tritt gebracht zu haben.

streams und vor allem templates sind meine Schwachstelle :-)
Man merkt halt doch, dass ich seit einem Jahr kein C++
mehr gemacht habe.

> Du bist schon recht weit gekommen, aber driftest in die falsche
> Richtung.

Mist.

>  Du wirst doch nicht vor dem Zielenlauf schlapp machen wollen?
> ;-)

Um ehrlich zu sein, hab ich im Moment keine Idee mehr.
Ich denke mal der ofstream-ostream Teil der Überlegung
stimmt.
Die Sache mit dem
ostream& ostream::operator<< (void*& val );
ist natürlich Unsinn, der kanns nicht sein. Ist ja
ein Literal, da wird das nichts mit der Referenz.

Also: Erzähl mal.

von Rolf Magnus (Gast)


Lesenswert?

Die ostream/ofstream-Geschichte ist nicht die Lösung.
Schreib mal die Operatoren-Aufrufe der Varianten mit und ohne flush() in 
Funktions-Syntax hin. Dann überleg dir, warum die Variante mit flush() 
ohne dieses nicht funktionieren kann.

Wenn du keine Lust mehr hast, kann ich es auch auflösen, sofern kein 
anderer auf die Idee kommt. Bisher waren alle anderen doch eher ruhig. 
Da war das Rätsel wohl doch etwas zu schwierig. ;-)

von Karl H. (kbuchegg)


Lesenswert?

> Schreib mal die Operatoren-Aufrufe der Varianten mit und ohne flush()
> in Funktions-Syntax hin.

War ne zeitlang weg.
Also dann:

  (std::ofstream("test.txt").flush()).operator<<( "foobar\n" );
  std::ofstream("test.txt").operator<<( "foobar\n" );

Nein,  warte.
Es gibt keinen member-op<< der einen const char * nimmt.
Das ist eine globale Funktionen.

  operator<<( std::ofstream("test.txt").flush(), "foobar\n" );
  operator<<( std::ofstream("test.txt"), "foobar\n" );

Irgendwie hab ich Tomaten auf den Augen. Ich sehs einfach
nicht. Reihenfolge der Argumentauswertung ist es nicht,
Slicing ist es auch nicht.

Jetzt reichts. Ich schmeiss mal den Compiler an und debugge
mich durch.

von Rolf Magnus (Gast)


Lesenswert?

Beide Varianten stimmen nicht. Es muß heißen:

  std::ofstream("test.txt").operator<<( "foobar\n" );
  operator<<( std::ofstream("test.txt").flush(), "foobar\n" );

Ohne flush() wird ja der für void* aufgerufen, und der ist ein Member.
Noch ein Tip: Der Stream ist ein temporäres Objekt.

von A.K. (Gast)


Lesenswert?

Muss ich jetzt extra nachsehen, wie die Lebensdauer von solchen Temps 
definiert ist? Dafür spricht auch, dass bei Digital beidesmal das 
gleiche rauskommt.

von A.K. (Gast)


Lesenswert?

typo: Digital Mars war gemeint.

von Karl H. (kbuchegg)


Lesenswert?

Rolf Magnus wrote:
> Beide Varianten stimmen nicht. Es muß heißen:
>
>   std::ofstream("test.txt").operator<<( "foobar\n" );

> Ohne flush() wird ja der für void* aufgerufen, und der ist ein Member.


Den versteh ich nicht. Warum soll der Compiler die Member-
Version nehme? Die Referenz die ich benutzt habe
http://www.cplusplus.com/reference/iostream/ostream/operator<<.html
listet nur eine Memberversion für einen void*& auf. Die
dürfte aber eigentlich (wegen Referenz) nicht genommen werden.

> Noch ein Tip: Der Stream ist ein temporäres Objekt.

Jetzt hast du mich vollends verwirrt, das temporäre Objekt
überlebt doch bis zum abschliessenden Sequence Point.

von Unbekannter (Gast)


Lesenswert?

Das ist ein schönes Beispiel dafür, dass C++ einfach nur kaputt ist.

Ich versteh auch nicht, warum sich der Code von Rolf falsch verhält. Und 
das, obwohl ich früher mal richtig viel in C++ geschrieben habe.

Aber es ist auch schon zu lange her, damit ich mir noch den ganzen Müll 
von C++ merken könnte.

Früher dachte ich mal, C++ sei eine Hochsprache. Heute weiß ich, C++ ist 
eine einzige Katastrophe.

von Karl H. (kbuchegg)


Lesenswert?

Hmm.
Diese Referenz ist unglaubwürdig. Da sind auch
überall sonst Referenzen drin. Da bin ich hineingefallen.

Für VC6 macht es übrigens auch keinen Unterschied
ob mit oder ohne flush().
Will aber nicht viel heissen. VC6 ist alt und bei weitem
nicht standardkonform. Ich probiers morgen mal mit dem
VC8


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.