Hallo,
ich habe diesen Code gefunden, der einen uint16_t zu einem Char-Array
macht. Der Vorteil ist, dass man nicht itoa benutzen muss.
Der Nachteil ist, dass free(str) nie ausgeführt wird.
Daher würde ich mich freuen, wenn ihr Verbesserungsvorschläge habt.
Bartosz B. schrieb:> Der Vorteil ist, dass man nicht itoa benutzen muss.
Warum dann nicht sprintf?
> Der Nachteil ist, dass free(str) nie ausgeführt wird.
Das kann nur der Aufrufer, der weiß, wann fertig.
Was soll der Code denn machen?
Das ist kein C, sondern C++, denn static_cast gibt es nur dort.
Bartosz B. schrieb:> Der Vorteil ist, dass man nicht itoa benutzen muss.
Warum ist das ein Vorteil, außer weil das keine Standardfunktion ist?
> Der Nachteil ist, dass free(str) nie ausgeführt wird.
Der Aufrufer muss es halt manuell ausführen. Nur der weiß ja, wann er
den Speicher nicht mehr braucht. Es gibt in C zwei gängige Methoden:
- die Funktion holt sich den Speicher dynamisch und übergibt dem
Aufrufer die Pflicht, den wieder freizugeben
- der Aufrufer stellt der Funktion bei Aufruf Speicher zur Verfügung und
die Funktion schreibt einfach nur dort hinein
> int length = snprintf(NULL, 0, "%d", number);
Der Format-String für int16_t wäre streng genommen
1
"%"PRIi16
Und warum snprintf statt sprintf?
> for (long long k = 0; k < 6ll; k++)
Warum long long für einen Schleifenzähler, wenn der nur bis 6 zählt?
> {> Number_as_String[k] = *(Pointer_pointing_to_the_NumberString +> k);
Warum auf der einen Seite den []-Operator und auf der anderen Seite die
umständliche Schreibweise für das selbe?
> if (k > 0ll && Number_as_String[k] == '\0') // If there is> space left, there is no need to overwrite it with nonsense.> {> break;> }
Macht diese ganze Schleife hier nicht im Prinzip das gleiche wie ein
ordinäres
Guten Morgen, Rolf!
Rolf M. schrieb:> Das ist kein C, sondern C++, denn static_cast gibt es nur dort.
Ja, also ja, grundsätzlich ist mein Code in C geschrieben. Ich arbeite
derzeit mit Visual Studio 2019 CE und habe ein C++ Projekt aufgemacht.
Daher kam seitens Visual Studio der Vorschlag, static_cast zu verwenden.
> Bartosz B. schrieb:>> Der Vorteil ist, dass man nicht itoa benutzen muss.>> Warum ist das ein Vorteil, außer weil das keine Standardfunktion ist?
Genau deswegen, so habe ich das gelernt. Sagst du mir nun, ich darf
freien Gewissens itoa verwenden?
>> Der Nachteil ist, dass free(str) nie ausgeführt wird.>> Der Aufrufer muss es halt manuell ausführen. Nur der weiß ja, wann er> den Speicher nicht mehr braucht. Es gibt in C zwei gängige Methoden:> - die Funktion holt sich den Speicher dynamisch und übergibt dem> Aufrufer die Pflicht, den wieder freizugeben> - der Aufrufer stellt der Funktion bei Aufruf Speicher zur Verfügung und> die Funktion schreibt einfach nur dort hinein
Ok, dann werde ich das einbauen. Kannst du mir bitte einen Vorschlag
geben? Aus dem Kopf würde ich sagen: str global definieren und dann
später in der main freigeben.
>> int length = snprintf(NULL, 0, "%d", number);>> Der Format-String für int16_t wäre streng genommen>
1
>"%"PRIi16
2
>
Verdammt, normalerweise achte ich auf so etwas sehr genau ...
> Und warum snprintf statt sprintf?
Kannte ich so noch nicht. C / C++ ist bei mir sehr lange her, ich habe
gerade wieder Lust drauf.
>> for (long long k = 0; k < 6ll; k++)>> Warum long long für einen Schleifenzähler, wenn der nur bis 6 zählt?
Weil es eine 64-bit-Adresse ist (ich debugge unter x64) und ich daher
richtig inkrementieren will.
>>> {>> Number_as_String[k] = *(Pointer_pointing_to_the_NumberString +>> k);>> Warum auf der einen Seite den []-Operator und auf der anderen Seite die> umständliche Schreibweise für das selbe?>
1
>>if(k>0ll&&Number_as_String[k]=='\0')// If there is
Bartosz B. schrieb:> habs nun so gemacht
Warum eine extra Funktion für 1 (wenn du buffer nicht brauchst) oder 2
Zeilen?
> Ich musste das Keyword static miteinbauen,
Das macht aber andere Probleme.
Bartosz B. schrieb:> Hallo,> ich habe diesen Code gefunden, der einen uint16_t zu einem Char-Array> macht.Bartosz B. schrieb:> grundsätzlich ist mein Code
Hast Du den Code nun gefunden (wo?) oder selber geschrieben?
Falls selbst, was soll der eigentlich tun. Falls Hausaufgabee, poste die
Aufgabe.
Der Code kommt zwar ohne itoa aus, macht aber auch etwas völlig anderes.
Falls Du nur itoa ersetzen willst, zeige den originalen Code mit itoa.
Bartosz B. schrieb:> Ich musste das Keyword static miteinbauen, da sonst die Warnung kam,> dass der Rückgabewert ungültig sein könnte.
Vorsicht, das Keyword Static hat in C zwei Bedeutungen abhängig davon,
wo es steht. In deinen Fall bedeutet es, das der Speicher Bereich
Buffer, genau einmal existiert und bei jeden Aufruf der Funktion
derselbe Bereich mit der aktuellen Zahl beschrieben wird. Solltest du
also so was machen.
1
a=uint16_t_to_String(15);
2
b=uint16_t_to_String(4);
3
4
if(a==b)
5
printf("a gleich b \n");
Wirst du dich Wundern, das a und b gleich sind. Da sie auf den gleichen
Speicher zeigen.
Bartosz B. schrieb:>>> for (long long k = 0; k < 6ll; k++)>>>> Warum long long für einen Schleifenzähler, wenn der nur bis 6 zählt?>> Weil es eine 64-bit-Adresse ist (ich debugge unter x64) und ich daher> richtig inkrementieren will.
Ich glaube, du brauchst noch (wieder?) Grundlagen. Überlege nochmal, was
dein Zähler macht (Wertebereich und notwendige Anzahl Bits) und ob es
tatsächlich eine Adresse ist.
Weshalb würde denn falsch inkrementiert, wenn du nur uint8_t nutzen
würdest?
Bartosz B. schrieb:> Guten Morgen, Rolf!> Rolf M. schrieb:>> Das ist kein C, sondern C++, denn static_cast gibt es nur dort.> Ja, also ja, grundsätzlich ist mein Code in C geschrieben. Ich arbeite> derzeit mit Visual Studio 2019 CE und habe ein C++ Projekt aufgemacht.> Daher kam seitens Visual Studio der Vorschlag, static_cast zu verwenden.
In C++ sollte man auch den static_cast bevorzugen, aber der C-Stil-Cast
geht genauso. Deine Nutzung ist aber nicht so ganz konsistent:
Bartosz B. schrieb:> char* str = (char*) malloc(static_cast<size_t>(length) + 1);
Links vom malloc benutzt du einen C-Cast, rechts einen static_cast. In C
wird übrigens emfohlen, den ersten Cast wegzulassen. In C++ ist er aber
notwendig.
>> Bartosz B. schrieb:>>> Der Vorteil ist, dass man nicht itoa benutzen muss.>>>> Warum ist das ein Vorteil, außer weil das keine Standardfunktion ist?> Genau deswegen, so habe ich das gelernt. Sagst du mir nun, ich darf> freien Gewissens itoa verwenden?
Es gibt viele Funktionen, die nicht Standard sind. Wenn du itoa
verwendest, wird natürlich die Portabilität des Code eingeschränkt. Das
heißt aber nicht, dass man sie auf gar keinen Fall nutzen sollte.
> Ok, dann werde ich das einbauen. Kannst du mir bitte einen Vorschlag> geben? Aus dem Kopf würde ich sagen: str global definieren und dann> später in der main freigeben.
Wie du den string definieren musst, hängt davon ab, wo er nachher
verwendet werden soll.
>>> for (long long k = 0; k < 6ll; k++)>>>> Warum long long für einen Schleifenzähler, wenn der nur bis 6 zählt?> Weil es eine 64-bit-Adresse ist (ich debugge unter x64) und ich daher> richtig inkrementieren will.
Wie breit die Adressen sind, kann dir an der Stelle egal sein. Wenn du
einen allgemeinen Typ für so etwas willst, der sich aber an die
jeweilige Plattform anpasst, kannst du z.B. size_t nehmen. Aber
funktionieren würde hier prinzipiell jeder beliebige Integer-Typ.
> *Edit:*> habs nun so gemacht> const char* uint16_t_to_String(uint16_t number)> {> static char buffer[6]{};> sprintf(buffer, "%d", number);> return buffer;> }> Ich musste das Keyword static miteinbauen, da sonst die Warnung kam,> dass der Rückgabewert ungültig sein könnte.
Kann man machen, aber dann musst du bedenken, dass der String bei jedem
Aufruf der Funktion überschrieben wird und dass sie nicht reentrant ist.
Das heißt, es wird zu Problemen kommen, wenn du die Funktion aus
mehreren Threads gleichzeitig aufrufst.
Was ich als zweite Variante genannt hatte, war, dass dein
uint16_t_to_String einen weiteren Parameter bekommt, der ein Zeiger auf
den Speicherbereich ist, wo die Funktion ihr Ergebnis hinschreiben soll.
Dann kannst du dir auch die anschließende Kopieraktion sparen, weil du
es gleich in den Zielstring schreiben kannst.
A. S. schrieb:> Das kann nur der Aufrufer, der weiß, wann fertig.
Oder der Empfänger, der diese Information bearbeitet und auswertet.
Wird free() in der oder von der Quelle aufgerufen, dann würde dem
Empfänger die Information nicht mehr zur Verfügung stehen und auf einen
ungültigen Zeiger zugreifen.
Es kann nicht schaden mit free() den Zeiger auf NULL zu setzen. Damit
kann später die Gültigkeit überprüft werden.
Gerald K. schrieb:> Es kann nicht schaden mit free() den Zeiger auf NULL zu setzen. Damit> kann später die Gültigkeit überprüft werden.
Dann ist aber ein Fehler im Programm.
Hallo zusammen,
ersteinmal möchte ich mich für die Antworten bedanken.
Er ist keine Hausaufgabe, ich bin nicht mehr an der Uni. Ich
programmiere nur privat 🙂
Dieser Code hier
kommt von Stackoverflow, allerdings habe ich die Seite nicht mehr im
Browserverlauf. Ist zu lange her, da ich nur am Wochenende programmiere
und es länger her ist. Jedenfalls habe ich nach "C Int to String"
gegoogelt. Der restliche Code in meinem Programm kommt einzig und allein
von mir.
Und auf Stackoverflow habe ich auch gelesen, dass itoa nicht mehr
Standard wäre. Aber Stackoverflow weiß auch nicht alles. Das
**static_cast<size_t>** hat Visual Studio mir vorgeschlagen. Und das
Problem, dass free(str) nicht ausgeführt wird, habe ich mit einem
Analysetool bemerkt.
Um es kurz zu machen: Ich werde nun itoa verwenden, da Imonbln und ihr
alle eigentlich mich auf das Problem mit dem Keyword static aufmerksam
geamcht habt. Ich habe heute früh noch beim Debuggen gesehen, dass der
Speicherbereich immer gleich ist, habe aber nicht die Gefahr gesehen –
danke für den Hinweis!
Die Schleife
1
for(longlongk=0;k<6ll;k++)
ist nun raus. Muss man denn grundsätzlich kein long long hernehmen, um
einen Pointer zu inkrementieren? Beispiel:
1
....=*(Pointer_pointing_to_the_NumberString+k)
erhöht ja erst die Adresse und holt davon den Wert. – Habe ich gedacht.
Aber Rolf M. hat das bereits beantwortet.
Danke auch an der Stelle für das schöne Wort réentrant 🙂
PS: Worum geht es hier eigentlich?
Ich möchte die C-Strings (also keine Strings sondern Char-Arrays) "A1",
"A2", "B1" (samt den Anführungszeichen) kreieren und dazu mache ich nun
sowas:
Das brauche ich, um eine xml-Datei einzulesen und die Values "A1" etc zu
finden. Weil das Einbinden von DLLs über Nuget um eine Excel-Datei
einzulesen nicht funktioniert hat.
In der Excel-Datei habe ich drei Spalten: in der linken stehen
Datumsangaben, in der Mitte kann eine 1 oder nichts stehen, rechts
steht immer eine 1 oder eine 0 (aber immer etwas).
1
01.01.2000 1 1
2
02.01.2000 1
3
03.01.2000 1
Das Ganze hatte natürlich Probleme zur Folge. Weil in der xml nun für
"B1"
1
<v>1</v>
stand und für "B2" nicht.
Das Einlesen der xml funktioniert aber bereits!! Ich wollte mich hier
nur einmal bezüglich der Int-to-String-Geschichte melden. Ich habe
allerdings keine Schwierigkeiten damit, euch den gesamten Code zu zeigen
– wenn ihr Lust habt. Ist allerdings etwas mehr. 269 Zeilen. Und ich
habe noch nicht die Werte zusammenhängend gespeichert. Das muss noch
gemacht werden.
Bartosz B. schrieb:> kommt von Stackoverflow,
Das free steht in dem Code als Erinnerung, dass es gemacht werden muss.
Oder hättest du daran gedacht?
> Und auf Stackoverflow habe ich auch gelesen, dass itoa nicht mehr> Standard wäre.
Das gehörte noch nie einem C-Standard an.
(wenn man C89 als ersten Standard annimmt, davor gab es viele Varianten)
Ist dir die Mächtigkeit von der printf-Familie überhaupt bewußt?
Deine ganz strcat-Orgie ist damit ein Einzeiler (siehe Beitrag von
foobar)
Zudem ist dein Acell sehr knapp bemessen und die Magic Numbers \x22
machen den Code auch nicht lesbarer.
Bartosz B. schrieb:> Das Einlesen der xml funktioniert aber bereits!!
Das ist in C leider keine Garantie für richtigen Code
(So wie es aussieht, übersetzt du C mit einem C++ Compiler)
> Ich wollte mich hier> nur einmal bezüglich der Int-to-String-Geschichte melden. Ich habe> allerdings keine Schwierigkeiten damit, euch den gesamten Code zu zeigen> – wenn ihr Lust habt. Ist allerdings etwas mehr. 269 Zeilen.
269 Zeilen ist Nichts.
Wenn du das machst - es gibt bestimmt Optimierungen und Fehler - dann
aber als Anhang und nicht im Beitrag.
Bartosz B. schrieb:> itoa(cnt, Number_as_String, 10);> …foobar schrieb:>> Ich möchte die C-Strings "A1", "A2", "B1" (samt den> Anführungszeichen)>> kreieren> 1 char cell[16];> 2 ...> 3 sprintf(cell, "\"%c%u\"", 'A', 10);
Der letzte Parameter bei der oben gezeigten itoa-Variante ist die Basis,
der erste der int-Wert. (es gibt auch itoa ohne Basis)
Dann ist das eher:
sprintf(cell, "\"%c%d\"", 'A', cnt);
Da cnt aber als uint16_t definiert ist (warum eigentlich), wäre es dann
sprintf(cell, "\"%c%"PRIi16“\"", 'A', cnt);
Dirk B. schrieb:> Da cnt aber als uint16_t definiert ist (warum eigentlich), wäre es dann>> sprintf(cell, "\"%c%"PRIi16“\"", 'A', cnt);
Das wird allerdings nicht funktionieren, wenn er das als C++(>=11)
compiliert, da dort "%c%"PRIi16 als benutzerdefiniertes string-literal
interpretiert wird. Man braucht ein zusätzliches Leerzeichen:
1
sprintf(cell,"\"%c%"PRIi16"\"",'A',cnt);
Hier ist auch das Anführungszeichen nach dem PRIi16 gefixt. ;-)
Dirk B. schrieb:> Bartosz B. schrieb:>> kommt von Stackoverflow,>> Das free steht in dem Code als Erinnerung, dass es gemacht werden muss.> Oder hättest du daran gedacht?
Achso...nein.
> Ist dir die Mächtigkeit von der printf-Familie überhaupt bewußt?
Nein.
> Deine ganz strcat-Orgie ist damit ein Einzeiler (siehe Beitrag von> foobar)
Danke dafür.
Ich werde die .cpp-Datei hier hochladen, wenn ich wieder Zeit habe. Ich
muss gleich los zur Arbeit.
> Da cnt aber als uint16_t definiert ist (warum eigentlich)
Weil ich dachte, dass das reicht. Ich werd niemals über 65535 Zeilen in
meiner Excel-Datei haben.
Bartosz B. schrieb:> Ich werd niemals über 65535 Zeilen in> meiner Excel-Datei haben.
Und wir werden niemals mehr als 640kB RAM brauchen... ;)
Gerald K. schrieb:> Es kann nicht schaden mit free() den Zeiger auf NULL zu setzen.
free/delete setzt den Pointer nicht auf NULL, das muss man von Hand
machen. free/delete gibt nur den Speicher frei.
Bartosz B. schrieb:> Ich musste das Keyword static miteinbauen, da sonst die Warnung kam,> dass der Rückgabewert ungültig sein könnte.
Natuerlich.
1
intfoo(void)
2
{
3
intlocal_var=0;
4
5
returnlocal_var;// es wird der WERT zurueck gegeben
6
}
7
8
int*bar(void)
9
{
10
intlocal_var[6]={0};
11
12
returnlocal_var;// local_var ist ein Array, es wird nur die STARTADRESSE
13
// des Arrays zurueck gegeben. Nach verlassen der
14
// Funktion ist die Adresse/die Daten an dieser Adresse
15
// nicht mehr gueltig.
16
}
17
18
19
int*foobar(void)
20
{
21
staticintlocal_var[6]={0};
22
23
returnlocal_var;// local_var ist ein Array, es wird nur die STARTADRESSE
24
// des Arrays zurueck gegeben. Wegen static liegt
25
// local_var nicht im Stack der Funktion foobar, und ist
26
// deswegen auch nach verlassen der Funktion gueltig.
Bartosz B. schrieb:> char Acell[5]{};> strcat(Acell, "\x22"); // "> strcat(Acell, "A");> strcat(Acell, Number_as_String);> strcat(Acell, "\x22"); // "
Acell ist viel zu klein um das alles aufzunehmen.
= {0}; schrieb:> Acell ist viel zu klein um das alles aufzunehmen.
So lange Number_as_String nur einstellig ist, reicht es gerade.
Kaj schrieb:> Bartosz B. schrieb:>> Ich werd niemals über 65535 Zeilen in>> meiner Excel-Datei haben.> Und wir werden niemals mehr als 640kB RAM brauchen... ;)
Excel selbst konnte lange Zeit nicht mehr als 65535 Zeilen.
Bartosz B. schrieb:> strcat(Acell, "\x22"); // "> strcat(Acell, "A");> strcat(Acell, Number_as_String);> strcat(Acell, "\x22"); // "
wenn du sowieso mit sprintf arbeitest, dann pack doch alles rein:
Rolf M. schrieb:> Excel selbst konnte lange Zeit nicht mehr als 65535 Zeilen.
Stimmt, das ist richtig. Ich glaube seit Office 2010 kann Excel mehr,
Mittlerweile sind es, glaube ich, 2^20 Zeilen.
Bartosz B. schrieb:> Weil ich dachte, dass das reicht. Ich werd niemals über 65535 Zeilen in> meiner Excel-Datei haben.
Dein Acell ist nur für einstellige Zeilen ausreichend dimensioniert, da
reicht auch ein char.
Da ist ein int mehr als ausreichend und kommt ohne viel gecaste aus.
int hat die native Größe auf dem jeweiligen System. Damit kann der
Prozessor am Besten rechnen.
Und dafür gibt es dann auch uint16_least_t oder uint16_fastest_t.
Die xint00_t Typen sind in den wenigsten Fällen die richtige Wahl.
900ss D. schrieb:> Dirk B. schrieb:>> Die xint00_t Typen sind in den wenigsten Fällen die richtige Wahl.>> Erklärung?
Weil sie eine feste Größe erzwingen. Das braucht man nur dort, wo man
direkt mit Hardware-Registern oder anderen Systemen binär kommuniziert
und daher ein bestimmtes Datenformat einhalten muss.
Rolf M. schrieb:> Weil sie eine feste Größe erzwingen.
Die aktuell existrierenden Implementierungen der Typen aus der stdint.h
ist per typedef auf die Standard-POD-Typen. Es gibt im ganzen
C/C++-Universum keine POD-Datentypen mit flexibler Länge.
Oliver
Oliver S. schrieb:> Rolf M. schrieb:>> Weil sie eine feste Größe erzwingen.>> Die aktuell existrierenden Implementierungen der Typen aus der stdint.h> ist per typedef auf die Standard-POD-Typen. Es gibt im ganzen> C/C++-Universum keine POD-Datentypen mit flexibler Länge.
Außer [u]intXX_t-Typedefs sind sämtliche Standard-C-Typen
plattformabhängig. int kann je nach Compiler z.B. 16, 24, 32 oder 64 Bit
breit sein, oder auch jede andere Größe, die mindesten 16 Bit beträgt.
Rolf M. schrieb:> int kann je nach Compiler z.B. 16, 24, 32 oder 64 Bit> breit sein,
Wer plattformübergreifend für völlig exotische oder sonstwie abstruse
Architekturen und Compiler programmieren muß, für den ist das ein Thema.
Und gerade dort wäre der Einsatz der xint_nnt-Typen für alles ausser
banalen Schleifenindizes angesagt. Da weiß man wenigstens, was man hat.
Oliver
Oliver S. schrieb:> Die aktuell existrierenden Implementierungen der Typen aus der stdint.h> ist per typedef auf die Standard-POD-Typen.
Und man weiß nicht, aus welchen Typen das gemacht wird.
Eigentlich möchte man ja nur, dass der erforderliche Wertebereich
abgedeckt wird. Und da sind die fastest oder least Typen sinnvoller.
Für die Zwecke des TO ist aber ein int ausreichen groß, schnell und
einfach.
(Der Thread steht in PC-Programmierung und es geht um Excel)
Rolf M. schrieb:> Weil sie eine feste Größe erzwingen
Die anderen Typen nutzen mindestens die Breite (Größe). Wo ist da der
Vorteil?
Höchstens evtl. etwas Geschwindigkeit oder noch mehr?
Also ich weiß lieber was ich hab ;)
Bartosz B. schrieb:> Der Vorteil ist, dass man nicht itoa benutzen muss.
Was soll daran ein Vorteil sein, Funktionen nicht zu benutzen, die
garantiert funktionieren und in der Regel besser optimiert sind, als
alles Handgemachte.
Deine Funktion ist ja von hinten durch die Brust ins Auge und ruft
snprintf doppelt auf, wozu?
Du meinst doch nicht ernsthaft, daß Deine Maschine abstürzt, wenn mal
ein paar Byte mehr reserviert werden.
Im Gegenteil, das malloc ist sogar besonders teuer, da es zusätzliche
Verwaltungsinformationen ablegen muß. Oftmals kann malloc daher eh keine
Häppchen <16 Byte reservieren, "65535" benötigt aber nur 6.
Im einfachsten Fall legt der Aufrufer ein Array für 6 Byte an und
übergibt dessen Adresse. Das erspart das ganze malloc/free Geraffel,
geht also am schnellsten.
Und falls die Funktion mehrfach benötigt wird, kann man das Array weiter
benutzen, d.h. man muß es nicht ständig neu anlegen.
Auch das handgemachte ins Ziel kopieren ist langsamer und aufwendiger
als die Libfunktion strcpy() und natürlich schlechter lesbar. Jeder muß
erstmal überlegen, wo ist der verdammte Haken, daß Du sie nicht
verwendest.