Skip to content

Instantly share code, notes, and snippets.

@lodi-g
Last active July 30, 2022 01:58
Show Gist options
  • Save lodi-g/05f8ef0a80ff2fc343950882549def79 to your computer and use it in GitHub Desktop.
Save lodi-g/05f8ef0a80ff2fc343950882549def79 to your computer and use it in GitHub Desktop.
Dump a variable content regardless of its type. Using the C11 _Generic keyword to emulate PHP's var_dump function.
#pragma once
/*
** Using printf, strlen and isprint
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/*
** Ignore warnings thrown by GCC on casts of different size.
** The whole goal of this is to NOT know the size at compile time.
*/
#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
/*
** All supported types
** char, int, _Bool, int *, char *, char ** and long
*/
typedef enum type_s
{
UNKNOWN,
CHAR,
INT,
BOOL,
PINT,
STRING,
PSTRING,
LONG,
ULONG
} type_t;
/*
** Prints an int *
*/
static void dump_pint(int *x)
{
int i;
for (i = 0; x[i] != -1; i++);
printf("int*(%i) [", i);
for (i = 0; x[i] != -1; i++)
printf("%i%s", x[i], x[i + 1] != -1 ? ", " : "");
printf("]");
}
/*
** Prints a char **
*/
static void dump_pstring(char **x)
{
int i;
for (i = 0; x[i]; i++);
printf("char**(%i) [", i);
for (i = 0; x[i]; i++)
printf("\"%s\"%s", x[i], x[i + 1] ? ", " : "");
printf("]");
}
/*
** Switch case on all supported types
** Prints <unsupported type> in case the type is not supported or not known
*/
// break; at each case clutters the code so using my own version :)
#define case break; case
#define default break; default
static void dump_var(type_t type, void *x)
{
switch (type)
{
case CHAR: printf("char('%s') ascii(%d)", isprint((char)x) ? ((char *)&x) : "<not printable>", (char)x);
case INT: printf("int(%i)", (int)x);
case BOOL: printf("bool(%s)", (_Bool)x ? "true" : "false");
case STRING: printf("string(%i) \"%s\"", strlen((char *)x), (char *)x);
case LONG: printf("long(%ld)", (long)x);
case ULONG: printf("unsigned long(%lu)", (unsigned long)x);
case PSTRING: dump_pstring((char **)x);
case PINT: dump_pint((int *)x);
default: printf("<unsupported type>");
}
}
// Don't mess up with others code
#undef case
#undef default
/*
** The public macro to dump a variable content
*/
#define DUMP(x) \
printf("%s:%d - %s - ", __FILE__, __LINE__, #x); \
{ \
type_t type; \
_Generic((x), \
char : type = CHAR, \
int : type = INT, \
_Bool : type = BOOL, \
char * : type = STRING, \
const char * : type = STRING, \
long : type = LONG, \
unsigned long: type = ULONG, \
char ** : type = PSTRING, \
const char **: type = PSTRING, \
int * : type = PINT, \
const int * : type = PINT, \
default : type = UNKNOWN); \
dump_var(type, (void *)x); \
} \
printf("\n");
#include <unistd.h>
#include <stdbool.h>
#include "dump.h"
int main(void)
{
char *a[] = { "abc", "def", "ghi", "jkl", NULL };
int b[] = {1, 2, 3, 4, -1};
bool c = true;
char d = 'a';
DUMP(1);
DUMP("abcde");
DUMP(a);
DUMP(b);
DUMP(c);
DUMP(d);
DUMP(9223372036854775804L);
printf("\n\n\n");
const int e = 1;
const char f[] = "abcde";
const bool g = false;
const char *h[] = { "mno", "pqr", "rst", NULL };
const char i = 10;
const int j[] = {1, 2, 3, 4, -1};
const long k = 9223372036854775804L;
DUMP(e);
DUMP(f);
DUMP(g);
DUMP(h);
DUMP(i);
DUMP(j);
DUMP(k);
printf("\n\n\n");
size_t l = 1;
ssize_t m = -1;
DUMP(l);
DUMP(m);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment