Unterschied der Methoden get und put bei Zeichensätzen?
-
Hallo Leute!
Bin Wiedereinsteiger und Anfänger in c++, bitte Text ganz durchlesen!
Bei der Portierung meiner Programme von c auf c++ sind mir einige gravierende
Unterschiede beim Handling der ein- und ausgelesenen Zeichen aufgefallen. Ein
simples Verschlüsselungsprogramm schluckt die Algorithmen nicht mehr.Der Grund liegt darin, das fgetc und fputc die Zeichen als int-Wert einlesen,
bei c++ dagegen als char, also signed char-Wert.Zunächst der Abschnitt in c, danach der in c++:
zeichen = fgetc(fquelle); /* slei=Zeichenenmenge beim einlesen */ if (zeichen == EOF) break; // naunco = "Nachricht uncodiert" if (kodierart == 0) { dummy = (unsigned char)zeichen + schluessel[codze]; if (dummy > 255) dummy -= 255; } if (kodierart == 1) { dummy = (unsigned char)zeichen - schluessel[codze]; if (dummy < 0) dummy += 255; } fputc(dummy, fziel); codze++; if (codze >= codelaenge - 1) codze = 0;
Selbstverständlich werden in C und in c++ beiden Dateien im Binärmodus
geöffnet.
Hier nun der angepasste Abschnitt in c++:dat_ein.get(inpletter); if (dat_ein.eof()) break; if (kodiermodus == 0) { outletter = inpletter + schluessel[codezaehler]; if (outletter > 127) outletter -= 127; } if (kodiermodus == 1) { outletter = inpletter - schluessel[codezaehler]; if (outletter < -128) outletter += 128; } dat_aus.put(outletter); codezaehler++; if (codezaehler >= codelaenge - 1) codezaehler = 0;
Nun die Rück-codierten Dateien. Zunächst der zu verschlüsselnde Quelltext:
1234567890ß´# qwertzuiopü+ asdfghjklöä yxcvbnm,.-
Hier sieht man, das der Text Umlaute enthält. zunächst das Ergebnis der
Rückcodierung in c:1234567890ß´# qwertzuiopü+ asdfghjklöä yxcvbnm,.-
Wie man sieht, ist die Kodierung einwandfrei möglich. Mit und ohne
Sonderzeichen, egal ob in der Quelldatei oder im Schüssel. So wie es
eigentlich sein sollte.
Nun das Ergebnis in c++:1234567890CB4# qwertzuiopC<+ asdfghjklC6C$ yxcvbnm,.-
Geplant wird später zusätzlich eine Bittransposition. Dazu wird eine Datei, die 16384 Zahlen, je eine von 0 bis 16383 enthält, erstellt.
Diese werden Zahlen durcheinander gewirbelt. Die Zahl der Möglichen Permutationen liegt bei 16384 faktorielle. Das dürfte in jedem Fall
jeden Knackversuch Stand halten. Danach wird die zu codende Datei häppchenweise als eindimensionales Array geladen und die
Schaltzustände der Bits mit Hilfe der Datei mit den 16384 Zahlenwerten vertauscht. Die Mögliche Verschlüsselungstiefe hängt von der
Mengenverteilung zwischen Highbits und Lowbits ab. SieheFormel von Euler: n = { (a+b)! /(a! *b!)}
Bei 50-prozentiger Verteilung ergibt das folgende Tabelle:
Bytezahl... Bitzahl .......mögliche Permutationen
Nibbel........4............6
1.............8............70
2.............16...........12870
4.............32...........6.0108E+8
8.............64...........1.83262E+18
16............128..........2.39511E+37
32............256..........5.76866E+75
64............512..........4.72553E+152
128...........1024.........4.48125e+306
256...........2048.........5.69709e+614
512...........4096.........1.30195e+1231
1024..........8192.........9.61516e+2436
2048..........16384 .......7.41605e+4929Weitere Versuche ergaben:
4096..........32768........?????? (ca. 45 Sekunden um die Zahlenfolge herzustellen)
8192..........65536........?????? (Herstellungszeit des Codes: 75 Sekunden bis 3Minuten)
16384.........131072.......?????? (Herstellungszeit des Codes: 15-25 Minuten!!!!!)Anzumerken ist, das Linux ja einen linearen Speicher hat, theoretisch könnte
man auch sämtliche Bits verschlüsseln. Leider ergaben meine Versuche jedoch,
das die Herstellungszeit der permutierten Zahlenfolgen exponentiell ansteigt.
Siehe obere Liste.Mein altes c-Programm schluckt
das alles einwandfrei und ist bereits fertig und getestet worden.
Aber leider nur für 32 Bit-Windows-Systeme tauglich. Den Code dazu
möchte ich hier aus allen sicherlich verständlichen Gründen nicht veröffentlichen. Dazu muss aber die Handhabung der einzelnen Bytes
einer Datei einwandfrei funktionieren. Dies geht nur, wenn die Bytes
als unsigned char vorliegen. Bei signed char funktioniert das leider
nicht, mußte ich feststellen. Dieses Programm ist nur der Testfall zum
üben.
Das ganze soll dann unter GPL ins Netz gestellt werden.Meine Frage:
Gibt es eine Möglichkeit in c++ die Bytes von vorn herein als unsigned char
einzulesen und abzuspeichern(siehe obrige Ausgabefehler), oder muß ich in den
sauren Apfel beißen und zumindest alles trotzdem in c programmieren?
Wer kann mir da helfen?
Ansonsten: Frohes Fest!
-
Nimm drei gute C++-Bücher und lerne von vorne neu. Schau in der FAQ dieses Forums nach guten Titeln und nicht bei Amazon-Rezensionen.
Lass das Portieren! Diese kleinen Programme sind bloß Fingerübungen, wovon keins länger als ne viertel Stunde zum Proggen braucht. Portieren dauert viel länger und es kommt kacke raus, wenn Du Dich am alten Stil festhältst.
-
Welchen Typ haben zeichen/dummy bzw. inpletter/outletter? Die fstream::get Funktion gibts auch mit int als Rückgabewert und auch als Variante mit Parameter für signed und unsigned char. Wenn du einfach unsigned char für alles benutzt, dann kann man sich deine Anpassungen wie
if (dummy > 255) dummy -= 255;
sparen, da sowieso alles Modulo 256 gerechnet wird.
-
Ach und mir fällt auch gerade dein Fehler auf. Du addierst die falschen Werte, in beiden Fällen! In der C Version möchtest du eigentlich 256 addieren/subtrahieren und in der C++ Version auch! Wenn du 127/128 addierst dann wird der Bereich [-128,-1] nach [0,127] verschoben. Dieser Bereich ist aber bereits belegt. Du möchtest eigentlich nach [128,255] verschieben.
-
Bei mir streikt der compiler wenn ich ios::get nicht mit char, sondern mit
unsigned char betreibe. Jetzt wandle ich die Typen einfach mit Addition,
bzw. mit Substraktion in die jeweilig gewünsten Tyen um.
Ich dachte, es geht auch für schreibfaule wie mich.In meinen C++ Büchern
werden die Methoden get und put (nur mit char) ganz kurz angerissen. Der Rest
wird für Strings verbraucht. Auf Bitoperationen zur Verschlüsselung
wir in keinen Buch eingegangen, das ich kenne.Es wurmt mich nur, das die Sonderzeichen so schwierig in c++ gehandhabt
werden müssen.Alle Beispiele die ich im Netz fand, waren mit char (signed char), keines
mit int oder unsigned char geschrieben. Beispiele mit unsigned char oder int
für get und put bei c++ habe ich noch nicht gesehen. Ist das Abhängig vom Compiler?
-
Sorry hab in der Doku ein 'nicht' überlesen. Die get Funktion wo man das Zeichen als Parameter kriegt ist doch nicht überladen für unsigned/signed char. Aber die Variante ohne Parameter hat einen int als Rückgabewert. Damit könntest du sowas schreiben:
unsigned char c = dat_ein.get();
-
Shit happens, said Forest Gump. ******* Kann passieren. Ich habs gelöst:
Ich habe mir zwei kleine Funktionen geschrieben:
//Umwandlung von signed char zu int int chartouint(char letter) { int rewer; if ( letter < 0) rewer = letter + 256; else rewer = (int)letter; return rewer; } //Umwandlung von signed char zu int char uinttochar(int letter) { char rewer; if ( letter > 127) rewer = letter - 256; else rewer = (int)letter; return rewer; }
die Umwandlung findet nun wie folgt statt:
void TestDatei::codedecode(void) { int codze, slei, intkey; QMessageBox *msgBox = new QMessageBox(this); std::fstream dat_ein; // std::fstream std::fstream dat_aus; // std::fstream /* Initialisiert die Dateilänge, einser, und Nuller mit Null, um richtig zäehlen zu können*/ dateilaenge = 0; einser = 0; nuller = 0; codze = 0; char *slussel = schluesselcode.toAscii().data(); // kopiert einen QString in einen ASCII-String char *finam = datnam.toAscii().data(); // kopiert einen QString in einen ASCII-String dat_ein.open(finam, std::fstream::in | std::fstream::binary); char *zielfinam = zieldateiname.toAscii().data(); // kopiert einen QString in einen ASCII-String dat_aus.open(zielfinam, std::fstream::out | std::fstream::binary); dat_ein.seekg(0, std::fstream::end); dateilaenge = dat_ein.tellg(); dat_ein.seekg(0, std::fstream::beg); if (!dat_ein ) { msgBox->setText("Datei konnte nicht geoeffnet werden!"); msgBox->show(); } for (slei = 0; slei < dateilaenge; slei++) { dat_ein.get(inpletter); if (dat_ein.eof()) break; einletter = atouint(inpletter); dum = atouint(slussel[codze]); if (kodiermodus == 0) erge = einletter + dum; if (kodiermodus == 1) erge = einletter - dum; if (erge > 255) erge -= 255; if (erge < 0) erge += 255; outletter = uinttochar(erge); dat_aus.put(outletter); codze++; if (codze >= codelaenge) codze = 0; } dat_ein.close(); dat_aus.close(); msgBox->setText("Datei wurde gecodet und abgespeichert!"); msgBox->show(); }
Ist zwar mit QT geschrieben, aber für c++ durchaus brauchbar.
Ich schreibe wenn es geht zuerst die c++ Konsolenanwendung,
danach erst wird (wenn ich Lust dazu habe) eine QT-Version
geschrieben. Soll ja mit 50 Jahren auf dem Buckel kein neuer
Beruf werden (Was Gott verhüten möge, nach seinem Willen) es
soll ein Hobby bleiben.
-
Gibt es irgendwo eine online-Dokumentation, für die Methode ios:get()?
bei mir sind nur Beispiele und Angaben mit dem Typ char gegeben:Autor: Stanley B. Lippman
Titel: C++ Einführung und Leitfaden
Verlag: Addison Wesley
ISBN: 0-201-54848-8Autor: Andre Willms
Titel: C++ Programmierung
Verlag: Addison Wesley
ISBN: 3-8273-1152-7Autor: Dirk Louis
Titel: C/C++ Kompendium
Verlag: Markt&Technik
ISBN: 3-8272-5386-1Autor: Ulla Kirch-Prinz / Peter Prinz
Titel: C++ Lernen und professionell anwenden
Verlag: mitp
ISBN: 3-8266-1534-4Autor: Helmut Erlenkötter
Titel: C++ Objektorientiertes Programmieren von Anfang an
Verlag: rororo
ISBN: 3-499-60077-3Autor: Kaare Christian
Titel: Programmierung mit C++
Verlag: Microsoft Press
ISBN: 3-86063-310-4Autor: Stephen Randy Davis
Titel: C++
Verlag: mitp
ISBN: 3-8266-3151-XAutor: Burkard Lehner
Titel: KDE- und QT-Programmierung GUI-Entwicklung für Linux
Verlag: Addison-Wesley
ISBN: 3-8273-1753-3Tip:
Bei Wohnungsauflösungen/Wertstoffhöfen/Flohmärkten
lassen sich solche Sachen hamstern.
-
rustyoldguy schrieb:
if (erge > 255) erge -= 255; if (erge < 0) erge += 255;
Hier muss es auch 256 sein.
rustyoldguy schrieb:
Gibt es irgendwo eine online-Dokumentation, für die Methode ios:get()?
Ja es gibt zwei Online Referenzen die man bei Google ständig findet:
http://www.cplusplus.com/reference/istream/istream/get/
http://en.cppreference.com/w/cpp/io/basic_istream/get
-
Der Typ get() mit Rückgabewert int ist für C-Programmierung. Die anderen Datentypen sind für char. Der "Notnagel" hat geholfen. Mal schaun, wie es
Weitergeht.Danke!