Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
-
king-crash
- Beiträge: 740
- Registriert: 08.08.2006 12:07:56
- Lizenz eigener Beiträge: MIT Lizenz
Beitrag
von king-crash » 09.05.2014 09:10:42
Folgender Code
Code: Alles auswählen
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv)
{
uint8_t test;
const char str[] = "abc123def";
sscanf(str, "abc%"PRIu8"def", &test);
printf("%"PRIu8"\n", test);
return 0;
}
Gibt den Fehler
test.c: In function ‘main’:
test.c:10:2: warning: format ‘%u’ expects argument of type ‘unsigned int *’, but argument 3 has type ‘uint8_t *’ [-Wformat=]
sscanf(str, "abc%"PRIu8"def", &test);
Ich hab mal im Header nachgeschaut und da ist alles ohne Modifizierer angegeben, also PRIu8 -> "u".
Für meinen Geschmack sollte das doch als "hhu" definiert sein...
Steh ich auf dem Schlauch oder ist das Header kompletter Müll?
-
newdeb
- Beiträge: 134
- Registriert: 03.02.2011 11:11:21
- Lizenz eigener Beiträge: MIT Lizenz
- Wohnort: Frankfurt
Beitrag
von newdeb » 09.05.2014 10:28:55
Die Debian/GNU - inttypes.h enthält Makros für Printing und Scanning Formate:
/* Macros for printing format specifiers. */
...
/* Unsigned integers. */
# define PRIu8 "u"
...
/* Macros for scanning format specifiers. */
...
/* Unsigned decimal notation. */
# define SCNu8 "hhu"
Der C99-Standard sagt:
The following macros shall be defined. Each expands to a character string literal containing a conversion specifier, possibly modified by a length modifier,
(
http://pubs.opengroup.org/onlinepubs/00 ... pes.h.html)
Die Implementierer dürfen sich offenbar gewisse Freiheiten herausnehmen.
-
king-crash
- Beiträge: 740
- Registriert: 08.08.2006 12:07:56
- Lizenz eigener Beiträge: MIT Lizenz
Beitrag
von king-crash » 14.05.2014 09:52:05
Hm die Sache ist doch aber merkwürdig.
Gehen wir mal vom printf aus
Beim Funktionsaufruf wird ein Byte auf den Stack geschoben aber der Funktion durch "%u" suggeriert es wären 4.
Oder werden bei x86 immer 4 Byte gepusht? Wenn ich mal Zeit habe werf ich den Disassembler an...
-
newdeb
- Beiträge: 134
- Registriert: 03.02.2011 11:11:21
- Lizenz eigener Beiträge: MIT Lizenz
- Wohnort: Frankfurt
Beitrag
von newdeb » 14.05.2014 11:19:33
Der Format-Spezifizierer beeinflusst die Ausgabe, nicht die Übergabe der Inhalte in der variablen Argumentliste in printf.
Letzteres sollten die va_* Makros (STDARG(3)) korrekt erledigen, auch unter Beachtung der Parametertypen.
-
wanne
- Moderator
- Beiträge: 7548
- Registriert: 24.05.2010 12:39:42
Beitrag
von wanne » 14.05.2014 12:06:03
Code: Alles auswählen
#include <stdio.h>
#include <inttypes.h>
int main(int argc, char **argv)
{
uint8_t test;
const char str[] = "abc123def";
sscanf(str, "abc%"SCNu8"def", &test);
printf("%"PRIu8"\n", test);
return 0;
}
rot: Moderator wanne spricht, default: User wanne spricht.
-
king-crash
- Beiträge: 740
- Registriert: 08.08.2006 12:07:56
- Lizenz eigener Beiträge: MIT Lizenz
Beitrag
von king-crash » 14.05.2014 13:44:32
Soweit mir bekannt ist expandiert va_arg(typ) zu etwas wie salopp hole_bytes_vom_stack(sizeof(typ)).
D.h. eigentlich holt die printf Funktion anhängig vom Formatspezifizierer eine gewisse Anzahl Bytes vom Stack.
Also bei "%hhd" 1 und bei "%d" 4.
Wenn ich jetzt ein uint8 oder char nur 1 Byte übergebe aber mit "%d" 4 Bytes vom Stack hole müsste es doch krachen...
Habe ich da einen Denkfehler?
-
newdeb
- Beiträge: 134
- Registriert: 03.02.2011 11:11:21
- Lizenz eigener Beiträge: MIT Lizenz
- Wohnort: Frankfurt
Beitrag
von newdeb » 14.05.2014 14:28:45
king-crash hat geschrieben:Habe ich da einen Denkfehler?
Nein, würde ich nicht sagen, aber die Compiler machen da geheimnisvolle Dinge, genannt "
default argument promotions":
Since the prototype doesn't specify types for optional arguments, in a call to a variadic function the default argument promotions are performed on the optional argument values. This means the objects of type char or short int (whether signed or not) are promoted to either int or unsigned int, as appropriate; and that objects of type float are promoted to type double. So, if the caller passes a char as an optional argument, it is promoted to an int, and the function can access it with va_arg (ap, int).
http://www.gnu.org/software/libc/manual ... adics.html
-
king-crash
- Beiträge: 740
- Registriert: 08.08.2006 12:07:56
- Lizenz eigener Beiträge: MIT Lizenz
Beitrag
von king-crash » 14.05.2014 17:52:36
Ah sehr interessant, besten Dank.
Obwohl ich das Verhalten als mittelschweren Schwachsinn bezeichnen würde, insbesondere hinsichtlich der float zu double konvertierung.
Deshalb auch der Unterschied zum SCN, da hier über Pointer direkt auf die richtigen Größen zugegriffen werden muss.