stream manipulieren mit iomanip
-
hallo,
wenn ich den code mit dev-cpp und g++ compiliere dann funzt es prima, bei visual studio 2003 .net mit msvc bekomm ich einen error:
Debug Assertion Failed!
File: istype.c
Line: 68
Expression: (unsigned)(c + 1) <= 256und warum braucht der msvc auch noch die haeder: #include <cctype> und der g++ nicht??
n8
#include <string> #include <iostream> #include <iomanip> using namespace std; class Parser { std::string s; public: Parser(const std::string& s):s(s) { } void output(std::ostream& o) const { for(std::string::const_iterator i=s.begin();i!=s.end();i++) { if(std::isalnum(*i)) o<<*i; else o<<'%'<<std::hex<<std::setw(2)<<std::setfill('0')<<(int)*i; } } }; std::ostream& operator<<(std::ostream& o,const Parser& f) { f.output(o); return o; } int main(int argc, char *argv[]) { std::cout<<Parser("§§§$$$göää#*%%&/==?`!$$€€@@@***dgdfgdg\n§§")<<std::endl; return 0; }
-
Der gcc sollte auch cctype brauchen, denn dort kommt isalnum her. Evtl. zieht einer der anderen Header den beim gcc.
Auf welcher Zeile in deinem Programm bleibt er denn hängen? (siehe Stacktrace) Der Grund scheint doch zu sein, dass da ein char einen Wert > 255 hat, was ja eigentlich nicht sein dürfte. Ist vielleicht irgendwas mit Multibyte-Zeichensätzen aktiviert? (auch wenn das eigentlich so nicht übersetzen dürfte...)
Und:
Parser(const std::string& s):s(s) { }Lokale Namen zu verdecken ist extrem unschön.
-
7H3 N4C3R schrieb:
Und:
Parser(const std::string& s):s(s) { }Lokale Namen zu verdecken ist extrem unschön.
das macht hier aber nichts, da der lokale name nur dazu verwendet wird,den nicht ganz so lokalen klassenmember zu initialisieren.
//edit und ist in dem sinne auchs chön, da man sich keine 2 namen für das selbe ding ausdenken muss
-
Wie würdest Du entscheiden?
void f( int i) { int i = i; }Dieser Code ist Unfug, da i mit sich selbst intialisiert wird und nicht etwa mit dem übergebenen i. Kann ein aktueller gcc auch vor warnen. (-Wshadow -Wself-init , wenn mich nicht alles täuscht)
Um solche eventuellen Verwirrungen sofort auszuräumen gilt bei uns die Code-Richtlinie, dass niemals (lokale) Namen verdeckt werden dürfen. Argumente lassen sich z.B. mit einem vorangestellten a markieren.
-
Du vergleichst grade äpfel mit birnen. Du betreibst funktionsparameter shadowing mittels einer lokalen variable, während hier anfangs von einem andren problem ausgegangen wurde(shadowing eines klassenmembers durch funktionsparameter). Diese probleme werden grundsätzlich anders gelöst.
Wieso ich das a für argumente in funktionsnamen nicht gut finde: das ist eine redundante information für den benutzer dieser funktion. In zeiten wo fast jede IDE code completion in irgendeiner Form unterstützt, sollten funktionsnamen nur die wichtigsten informationen beinhalten, um den benutzer nicht zu verwirren. ein "a" am anfang zählt da sicher nicht zu, da der benutzer ja schon weiß, dass der parameter ein argument ist(dafür muss er aber mindestens einmal mehr in die doku schauen, damit er weis, was das a bedeuted).
Wesentlich effektiver halte ich da den ansatz, interne variablennamen zu verändern, zb klasssenmember mit einem m_ am anfang oder einem _ am ende des namens. Am sinnvollsten ist aber, namen garnicht irgendwie anpassen zu müssen. Und dazu bietet C++ einige Möglichkeiten:
während die initialisierungsliste die unterscheidung der namen automatisch erledigt(siehe code am anfang), bietet sich für den rest der fälle die möglichkeit, namensprobleme mithilfe des schlüsselwortes "this" zu lösen. Da diese namensprobleme normalerweise nur in gettern und settern auftreten, tritt this nur an wenigen stellen auf, der rest des codes wird nicht verändert.
-
Eine vernünftige Benamsung von Klassenmembern sollte sowieso immer vorliegen, das war auch nur für obiges Beispiel gedacht. Wenn man in einem Programmierer-Team arbeitet wo jeder den Code verstehen muss/soll(!), kann man nicht erwarten, dass einem jeder den Standard runterbeten kann und nicht 100%ig intuitive Ausdrücke sofort richtig zuordnen kann. Die Geschichte mit der Intialisierungsliste ist so ein schönes Beispiel. Ich finde, man sollte Code nicht gerade so schreiben, dass man erst 3 Stunden überm Standard brüten muss um rauszufinden, dass er richtig arbeitet, sondern intuitiv verständlich.
Namensprobleme mit this-> zu lösen empfinde ich persönlich als eine Krücke und sehr hässlich.
-
ich finde otze auch sehr hässlich
-
@otze und 7H3 N4C3R
Bitte wieder auf das Ursprungsthema zurückkommen. Wenn ihr weiter über die Namen diskutieren wollt, macht dafür doch bitte einen neuen Thread auf.
-
Wie es 7H3 N4C3R bereits angesprochen hat, nimmt ein Zeichen wie z.B. § im MSVC einen größeren Wert an, als char das eigentlich kann. Bei VC wirft isalnum hier eine Assertion, der g++ rechnet es scheinbar periodisch auf ein char runter, weiß nicht. Um der Assertion vorzubeugen kannst du es selbst abfangen:
if((unsigned)(*i)<= 255) { if(std::isalnum(*i)) o<<*i; }
-
warum nimm denn isalnum überhaupt ein integer als parameter?? warum nicht (unsigned?) char?
-
Vermutlich um eben genau solche Fehler abfangen zu können. Alle Werte über 255 sind kein normales char mehr. Und was kein Char ist, kann auch kein alphanumerisches Zeichen sein. Würde die Funktion jetzt char als Parameter haben, ihr aber ein int übergeben wird, wird das int zu char gecastet. So wäre ein Wert von 322 (256+66) plötzlich nur noch 66 (entspricht
und somit ein alphanumerisches Zeichen -> die Funktion liefert true zurück, was ja ein Fehler ist.
-
hallo,
problem konnte lokalisiert werden und es tritt beim manipulieren dieser zeichen auf:
std::cout<<Parser("§")<<std::endl;std::cout<<Parser("Ä")<<std::endl;std::cout<<Parser("Ö")<<std::endl;probleme gibt es noch bei: Ü, ü, ä, ö, ², ³, ´
einstellung für Character Set:
Use Multi-Byte Character Sethab das dann weggeschalten...funzte aber auch nicht;-(
auch wenn ich i in (unsigned char) caste nicht...i ist also wie ich merke >= 255...klar könnt ich das mit der If abfangen...
aber will ja auch bei "´L" das erste zeichen manipulieren...cu
-
hier paar weitere infos:
code
std::cout<<Parser("§")<<std::endl;debug infos:
_ctype.c if ( ptloci != __ptlocinfo ) ptloci = __updatetlocinfo(); return __isalnum_mt(ptloci, c); <----error Call Stack Temp.exe!_chvalidator_mt(threadlocaleinfostruct * p=0x003231b8, int=-89, int mask=263) Line 68 + 0x2a Temp.exe!isalnum(int c=-89) Line 165 + 0x35cu
-
hmmmmmmmmm schrieb:
warum nimm denn isalnum überhaupt ein integer als parameter?? warum nicht (unsigned?) char?
Das wurde in diesem Forum schon ca. 1.7 Millionen mal erklärt. Genau wie die Tatsache, dass Code wie dieser:
for(std::string::const_iterator i=s.begin();i!=s.end();i++) { if(std::isalnum(*i)) ... }schlicht falsch ist.
Die Suchfunktion hilft interessierten sicher weiter. Allen anderen bleiben langweilige Wiederholungen erspart
-
ich bin nicht in der lage auch nur einen von den 1.7 millionen beiträgen zu finden

suche nach isalnum im c++ forum ergab ca. 10 treffer, wo aber überall nur die funktion verwendet wurde und nichts weiter dazu erklärt wird.
-
hmmmmmmmm schrieb:
ich bin nicht in der lage auch nur einen von den 1.7 millionen beiträgen zu finden

suche nach isalnum im c++ forum ergab ca. 10 treffer, wo aber überall nur die funktion verwendet wurde und nichts weiter dazu erklärt wird.
Jup. Erklärt wurde das Ganze bisher nur für andere "character classification"-Funktionen wie z.B. tolower oder toupper.
Schau z.B. mal hier:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-82570-and-start-is-30.html
Dort musst du die letzte Seite auswählen. Und ganz wichtig, nicht vergessen den letzten Link anzuklicken.Das Prinzip ist immer das selbe.
Zusammengefasst:
1. die Funktionen erwarten einen int, da sie zwei Sorten von Eingaben verarbeiten können:
a) alle Zeichen, die als *unsigned char* dargestellt werden können
b) EOF
Da nun EOF nicht gleichzeitig auch als ein gültiges Zeichen repräsentiert werden kann, muss ein Datentyp her, der mehr Werte als alle gültigen Zeichen aufnhemen kann -> int.2. Da die Funktionen ihre korrekt Funktionsweise nur unter a) und b) garantieren, muss der Aufrufer garantieren, dass sein Parameter a) oder b) erfüllt. Da char in C++ nun aber sowohl signed als auch unsigned char sein kann, ist die einzige Möglichkeit wie man a) garantieren kann die, dass man sein Zeichen nach unsigned char castet bevor man es an eine der Funktionen übergibt. Ansonsten ist das Verhalten für eine Platform auf der char == signed char gilt und für Zeichen die nicht im "basic execution character set" liegen undefinert. Und Zeichen wie 'ü' oder '§' sind nun mal nicht Teil des BECS.
Richtig wäre also:
for(std::string::const_iterator i=s.begin();i!=s.end();i++) { if(std::isalnum(static_cast<unsigned char>(*i))) ... }
-
hi, danke das beantwortet schon viele fragen!!
aber was mach ich nun mit ü und § usw?
ps.: der hmmmmmmmm bin nicht ich!!
cu
-
cplusplus. schrieb:
aber was mach ich nun mit ü und § usw?
Das kommt darauf an, was genau du erreichen willst. Erstmal musst diese Zeichen (wie oben beschrieben) nach unsigned char casten, bevor du sie an deine Klassifizierungsfunktion übergibst. Danach musst du dir über locales Gedanken machen. Das Standard-C-Lokale wird für isalnum(static_cast<unsigned char>('ü')) Null liefern, da 'ü' aus Sicht dieses locales kein alpha-numerisches Zeichen ist (das Englische-Alphabet enthält kein ü).
Wenn du dich aber nicht auf das Englische-Alphabet beschränken willst, dann musst du ein passendes Locale installieren. Z.B. ein Deutsches. Wie genau das geht, musst du deinem Compiler-Handbuch entnehmen, da die Locale-Strings nicht standardisiert sind.
Ein Beispiel:#include <ctype.h> #include <locale.h> #include <iostream> using namespace std; void check(const char* l) { cout << "ä ist laut " << l << " - locale "; if (isalnum(static_cast<unsigned char>('ä')) == 0) cout << "*kein*"; else cout << "*ein*"; cout << " alpha-numerisches Zeichen!" << endl; } int main() { const char* old = setlocale(LC_CTYPE, 0); check(old); if (const char* newLoc = setlocale(LC_CTYPE, "german")) { check(newLoc); } setlocale(LC_CTYPE, old); }
-
will diese codierung machen:
ö -> %F6
ä -> %E4
ü -> %FC
Ö -> %D6
Ä -> %C4
Ü -> %DC
§ -> %A7Z.B. ein Deutsches. Wie genau das geht, musst du deinem Compiler-Handbuch entnehmen, da die Locale-Strings nicht standardisiert sind.
ok gut, da ich visual studio 2003 .net habe werd ich mal google befragen...
also bei visual studio 2003 .net kann ich folgende einstellung machen:
Character Set:
- Not Set
- Use Unicode Character Set
- Use Multi-Byte Character Setwas ist da der unterschied...mir sagt nur unicode was...
cu
-
hi, hab das mit setlocale probiert und hier meine infos entnommen:
http://cplus.kompf.de/artikel/locale.html
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_language_and_country_strings.aspaber ich bring das nicht zum laufen;-(
cu