Compiler "überspringt" Byte bei Initialisierung?!



  • Nicht erschrecken, Post lang aber nicht kompliziert!
    Es scheint unmöglich, aber nachdem ich Stunden mit Debuggen verbracht habe, meine ich der Compiler veräppelt mich.

    Also: Es gibt da ein Tool, das generiert netterweise aus Fonts automatisch entsprechende arrays (nützlich für LCDs): http://www.eran.io/the-dot-factory-an-lcd-font-and-image-generator/

    Damit hab ich mir die ganze Palette an ASCII-Zeichen von '!' (0x21) bis '~' (0x7e) generiert, vgl. http://www.torsten-horn.de/techdocs/ascii.htm

    Eine der generierten Strukturen sieht so aus:

    typedef struct _font_char_info 
    { 
       std::uint8_t Charwidth; 
       std::uint16_t Offset;  // Das Offset ist interessant, es gibt den Byteabstand zwischen den Zeichen an
    }FONT_CHAR_INFO;
    

    Das vom "The dot factory" generierte Array sieht wie folgt aus (nicht erschrecken):

    const FONT_CHAR_INFO microsoftSansSerif_6ptDescriptors[] = 
    {
    	{1, 0}, 		// ! 
    	{3, 8}, 		// " 
    	{4, 16}, 		// # 
    	{4, 24}, 		// $ 
    	{7, 32}, 		// % 
    	{5, 40}, 		// & 
    	{1, 48}, 		// ' 
    	{2, 56}, 		// ( 
    	{2, 64}, 		// ) 
    	{3, 72}, 		// * 
    	{4, 80}, 		// + 
    	{1, 88}, 		// , 
    	{2, 96}, 		// - 
    	{1, 104}, 		// . 
    	{2, 112}, 		// / 
    	{4, 120}, 		// 0 
    	{2, 128}, 		// 1 
    	{4, 136}, 		// 2 
    	{4, 144}, 		// 3 
    	{4, 152}, 		// 4 
    	{4, 160}, 		// 5 
    	{4, 168}, 		// 6 
    	{4, 176}, 		// 7 
    	{4, 184}, 		// 8 
    	{4, 192}, 		// 9 
    	{1, 200}, 		// : 
    	{1, 208}, 		// ; 
    	{4, 216}, 		// < 
    	{4, 224}, 		// = 
    	{4, 232}, 		// > 
    	{4, 240}, 		// ? 
    	{8, 248}, 		// @ 
    	{5, 256}, 		// A 
    	{4, 264}, 		// B 
    	{5, 272}, 		// C 
    	{4, 280}, 		// D 
    	{4, 288}, 		// E 
    	{4, 296}, 		// F 
    	{6, 304}, 		// G 
    	{4, 312}, 		// H 
    	{1, 320}, 		// I 
    	{3, 328}, 		// J 
    	{4, 336}, 		// K 
    	{3, 344}, 		// L 
    	{5, 352}, 		// M 
    	{4, 360}, 		// N 
    	{6, 368}, 		// O 
    	{4, 376}, 		// P 
    	{6, 384}, 		// Q 
    	{4, 392}, 		// R 
    	{5, 400}, 		// S 
    	{5, 408}, 		// T 
    	{4, 416}, 		// U 
    	{5, 424}, 		// V 
    	{7, 432}, 		// W 
    	{5, 440}, 		// X 
    	{5, 448}, 		// Y 
    	{5, 456}, 		// Z 
    	{1, 464}, 		// [ 
    	{2, 472}, 		// \ 
    	{2, 480}, 		// ] 
    	{3, 488}, 		// ^ 
    	{4, 496}, 		// _ 
    	{2, 504}, 		// ` 
    	{4, 512}, 		// a 
    	{3, 520}, 		// b 
    	{4, 528}, 		// c 
    	{4, 536}, 		// d 
    	{4, 544}, 		// e 
    	{2, 552}, 		// f 
    	{4, 560}, 		// g 
    	{3, 568}, 		// h 
    	{1, 576}, 		// i 
    	{1, 584}, 		// j 
    	{3, 592}, 		// k 
    	{1, 600}, 		// l 
    	{5, 608}, 		// m 
    	{3, 616}, 		// n 
    	{4, 624}, 		// o 
    	{3, 632}, 		// p 
    	{4, 640}, 		// q 
    	{2, 648}, 		// r 
    	{4, 656}, 		// s 
    	{2, 664}, 		// t 
    	{3, 672}, 		// u 
    	{4, 680}, 		// v 
    	{6, 688}, 		// w 
    	{4, 696}, 		// x 
    	{4, 704}, 		// y 
    	{4, 712}, 		// z 
    	{2, 720}, 		// { 
    	{1, 728}, 		// | 
    	{2, 736}, 		// } 
    	{4, 744}, 		// ~ 
    };
    

    Jeder Buchstabe ist 8 Zeilen hoch, wird also in einem Byte gespeichert, wie z.B. nachfolgend das 'H':

    // @312 'H' (4 pixels wide)
    	0x90, // #  #
    	0x90, // #  #
    	0xF0, // ####
    	0x90, // #  #
    	0x90, // #  #
    	0x90, // #  #
    	0x00, //     
    	0x00, //
    

    Daher wird der Offset-Wert in microsoftSansSerif_6ptDescriptors auch brav jedes Mal um 8 Bytes erhöht. Wie man sieht ist das im Quelltext auch durchgängig korrekt.

    Problem:
    Ab dem Zeichen ']' (Offset 480) habe ich allerdings festgestellt, dass meine Zeichne-Routine immer das nachfolgende Zeichen (488. Nachfolgend statt 488 -> 496 usw.) gezeichnet hat. Dachte das hätte irgendwas mit std::uint16_t oder so zu tun. Dann hab ich mal das ganze Array in einer Datei gespeichert:

    ofstream file("dbg.txt");
    	for(int i=0; i<94; ++i) {
    		file<<i<<'\t'<<(char)(i+0x21)<<'\t'<<microsoftSansSerif_6ptDescriptors[i].Offset<<endl;
    	}
    

    Ausgabe:

    0	!	0
    1	"	8
    2	#	16
    3	$	24
    4	%	32
    5	&	40
    6	'	48
    7	(	56
    8	)	64
    9	*	72
    10	+	80
    11	,	88
    12	-	96
    13	.	104
    14	/	112
    15	0	120
    16	1	128
    17	2	136
    18	3	144
    19	4	152
    20	5	160
    21	6	168
    22	7	176
    23	8	184
    24	9	192
    25	:	200
    26	;	208
    27	<	216
    28	=	224
    29	>	232
    30	?	240
    31	@	248
    32	A	256
    33	B	264
    34	C	272
    35	D	280
    36	E	288
    37	F	296
    38	G	304
    39	H	312
    40	I	320
    41	J	328
    42	K	336
    43	L	344
    44	M	352
    45	N	360
    46	O	368
    47	P	376
    48	Q	384
    49	R	392
    50	S	400
    51	T	408
    52	U	416
    53	V	424
    54	W	432
    55	X	440
    56	Y	448
    57	Z	456
    58	[	464
    59	\	472
    60	]	488
    61	^	496
    62	_	504
    63	`	512
    64	a	520
    65	b	528
    66	c	536
    67	d	544
    68	e	552
    69	f	560
    70	g	568
    71	h	576
    72	i	584
    73	j	592
    74	k	600
    75	l	608
    76	m	616
    77	n	624
    78	o	632
    79	p	640
    80	q	648
    81	r	656
    82	s	664
    83	t	672
    84	u	680
    85	v	688
    86	w	696
    87	x	704
    88	y	712
    89	z	720
    89	z	720
    90	{	728
    91	|	736
    92	}	744
    93	~	0
    

    Der Compiler scheint also ab Zeile 60 bzw. Index 480 alles um +8 zu verschieben und für den letzten Array-Wert speichert er anstatt 744 einfach eine 0 😕 😕 😕 😕 😕

    Ich habe keine Ahnung, wer erklärt mir das Rätsel?



  • {2, 472},       // \
    

    Mach den Backslash da am ende der Zeile weg, der escaped das nachfolgende newline, wodurch die nächste Zeile noch in diese Zeile mit rückt, allerdings im Kommentar steht und somit nicht berücksichtigt wird.


  • Mod

    {2, 472},       // \
    

    Das ist ein Kommentar mit anschließendem Zeilen(anti-)umbruch. Das heißt, die nächste Zeile gilt als Verlängerung dieser Zeile und somit als Teil des Kommentars.

    edit: Zu langsam.



  • Sollte nicht jeder Compiler da eine Warnung ausspucken? gcc und clang zumindest tun das.

    Stell deinen Compiler bitte richtig ein und aktiviere Warnungen!



  • Was für ein mieser Fehler... ich danke euch... Da sollte ich den Entwicklern des Tools eine Meldung machen, damit das Zeichen da nicht mehr automatisch generiert wird.

    @bytheroot: Compiler ist der gcc und der hat bei mir nichts gemeldet (ich meine Default-Warnungen)



  • Bei gcc musst du mit -Wall kompilieren, sonst kriegst du nur sehr wenig Warnungen. Noch besser ist -Wall -Wextra -pedantic .


  • Mod

    AbsolutUnklar schrieb:

    @bytheroot: Compiler ist der gcc und der hat bei mir nichts gemeldet (ich meine Default-Warnungen)

    Default ist halt nur bei wirklich krassen Fehlern zu warnen. Mach mindestens "Wall" an! Ich mag auch "Wextra", wobei das aber etwas kontrovers ist, da man manche der dortigen Warnungen eher als stilistische Zwänge bewerten kann.


  • Mod

    Was für ein mieser Fehler... ich danke euch... Da sollte ich den Entwicklern des Tools eine Meldung machen, damit das Zeichen da nicht mehr automatisch generiert wird.

    Nicht ganz. Sag ihnen einfach sie sollen entweder /* */ Kommentare verwenden oder ein zusätzliches Newline am Ende jeder Kommentarzeile im entsprechenden Abschnitt einfügen (wobei letzteres mit einigen IDEs ggf. nicht funktioniert).


  • Mod

    Arcoth schrieb:

    Was für ein mieser Fehler... ich danke euch... Da sollte ich den Entwicklern des Tools eine Meldung machen, damit das Zeichen da nicht mehr automatisch generiert wird.

    Nicht ganz. Sag ihnen einfach sie sollen entweder /* */ Kommentare verwenden oder ein zusätzliches Newline am Ende jeder Kommentarzeile im entsprechenden Abschnitt einfügen (wobei letzteres mit einigen IDEs ggf. nicht funktioniert).

    Ich hoffe mal, dass die Entwickler selber auf eine passende Lösung kommen. Wobei /* */ Kommentare aber auch doof sind. Ich würde einfach alles in Anführungsstriche setzen. Das Zeichen heißt in C++ schließlich '\' , nicht \ .



  • SeppJ schrieb:

    Ich würde einfach alles in Anführungsstriche setzen.

    +1

    SeppJ schrieb:

    Das Zeichen heißt in C++ schließlich '\' , nicht \ .

    Das Zeichen heisst in C++ eigentlich '\\' . (Oder meinst du jetzt was anderes?)
    Und das wäre mir ehrlich gesagt egal. Es in einfache Hochkomma zu setzen sieht einfach halbwegs "vernünftig" aus, und verhindert mMn. viel effektiver als ein zusätzlicher Zeilenumbruch (wo schnell jemand auf die Idee kommen könnte den wegzumachen) dass Probleme auftreten.


Log in to reply