Kirjautuminen

Haku

Tehtävät

Koodit: C: Datan debug-tulostus heksamuodossa

Kirjoittaja: Metabolix

Kirjoitettu: 24.06.2008 – 24.06.2008

Tagit: teksti, koodi näytille, vinkki

Matalan tason ohjelmoinnissa – ja miksei muuallakin – on usein tarpeen saada debuggausta varten binaaridataa ulos tarkasteltavassa muodossa, usein siis heksadesimaaliesityksenä. Tässäpä siihen valmis funktio, joka tulostaa datan hieman tyypillistä heksaeditoria jäljitellen: ensin heksamuotoinen data ja reunassa tekstimuotoinen versio. Riville tulostuu tässä versiossa oletusarvoisesti 16 tavua.

Funktion ensimmäinen parametri on tiedosto, johon tulostetaan. Standardivirta stdout ohjautuu yleensä ruudulle, samoin virhevirta stderr. Toinen parametri on osoitin tulostettavaan dataan ja kolmas datan pituus tavuina.

Esimerkkiohjelmassa todetaan wide char -tyypin ja tavallisen char-tyypin ero, joka toki riippuu myös käytettävästä järjestelmästä.

Dump-funktio tarvittavien otsikkojen kera

#include <ctype.h>
#include <stdio.h>

#define ROW_BYTES (16)
#define NOT_GRAPH ('.')

void dump(FILE *out, const void *ptr, int len)
{
	const char *str = (const char *) ptr;
	int i, j;
	/* Koko data 16 tavun paloissa */
	for (i = 0; i < len; i += ROW_BYTES) {
		/* Ensin haluttu tavumäärä heksana */
		for (j = 0; j < ROW_BYTES && i + j < len; ++j) {
			fprintf(out, " %02x", (unsigned char)str[i+j]);
		}
		/* Jos dataa ei ollut riittävästi, täytetään loput tyhjällä */
		for (; j < ROW_BYTES; ++j) {
			fprintf(out, "   ");
		}
		/* Pieni rako */
		fprintf(out, "   ");
		/* Tulostetaan graafiset merkit ja muiden tilalle pisteitä */
		for (j = 0; j < ROW_BYTES && i + j < len; ++j) {
			fputc((isgraph(str[i+j]) ? str[i+j] : NOT_GRAPH), out);
		}
		/* Rivin loppuun rivinvaihto */
		fputc('\n', out);
	}
}

Esimerkkiohjelma

#include <wchar.h>

int main(void)
{
	/* Tulostettavat muuttujat */
	wchar_t wstr[] = L"teksti";
	char str[] = "teksti";
	int i = 1415926535;

	/* Dumppaillaan */
	printf("wstr:\n");
	dump(stdout, wstr, sizeof(wstr));
	printf("str:\n");
	dump(stdout, str, sizeof(str));

	/* Huomaa & (osoite), kun ei ole taulukko! */
	printf("i:\n");
	dump(stdout, &i, sizeof(i));
	return 0;
}

Esimerkkituloste

wstr:
 74 00 00 00 65 00 00 00 6b 00 00 00 73 00 00 00   t...e...k...s...
 74 00 00 00 69 00 00 00 00 00 00 00               t...i.......
str:
 74 65 6b 73 74 69 00                              teksti.
i:
 07 53 65 54                                       .SeT

Kommentit

Teuro [30.06.2008 15:20:47]

#

Hieno vinkki varmasti tarpeen ohjelman kehitysvaiheessa. Hyvin kirjoitetut ja asialliset kommentit.

Mieleen tulee ainoastaan tuo #define rivi, joka kannataisi kait esitellä const int ROW_BYTES = 16; Kääntäjä osaisi purkaa tietotyypin ja varoitella väärästä käytöstä. Näin olen sen itselleni antanut kertoa.

Muuten todella mainota jälkeä.

vehkis91 [05.07.2008 23:45:52]

#

Joo mutta eikös toi #define ole c:tä ja const int c++?

Metabolix [06.07.2008 12:35:48]

#

Ei, vaan #define on esikääntäjän komento ja const taas C-kielen avainsana. Näiden toimintaperiaate on täysin erilainen.

_Pete_ [05.08.2008 16:44:35]

#

Tähän liittyen loisto utility:

man xxd

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta