P
pozz
In C I can have a small set of numeric type variables: char, short,
int and long (ignoring long long), and their unsigned counterpart.
In one of my program, I have a lot of (about 200) numeric variables of
different types, signed and unsigned.
Now I want to create a generic function that shows the value of a
variable on the display with a format string dependent on the
variable, increase/decrease it inside a range dependent on the
variable and set it the new value.
I create the following code... do you have any suggestions or
improvements? It seems to me too complex to read (a lot of if(p-
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
signed char sc = -1;
unsigned char uc = UCHAR_MAX;
signed short ss = -1;
unsigned short us = SHRT_MAX;
signed int si = -1;
unsigned int ui = UINT_MAX;
signed long int sl = -1;
unsigned long int ul = ULONG_MAX;
typedef struct {
enum {
NUM_TYPE_SCHAR,
NUM_TYPE_UCHAR,
NUM_TYPE_SSHRT,
NUM_TYPE_USHRT,
NUM_TYPE_SINT,
NUM_TYPE_UINT,
NUM_TYPE_SLONG,
NUM_TYPE_ULONG,
} type;
void *ptr;
const char *fmt;
union {
signed char min_sc;
unsigned char min_uc;
signed short min_ss;
unsigned short min_us;
signed int min_si;
unsigned int min_ui;
signed long min_sl;
unsigned long min_ul;
} min;
union {
signed char max_sc;
unsigned char max_uc;
signed short max_ss;
unsigned short max_us;
signed int max_si;
unsigned int max_ui;
signed long max_sl;
unsigned long max_ul;
} max;
} num_t;
/* Just some example variables */
num_t num_sc = { NUM_TYPE_SCHAR, &sc, "%d degrees", { .min_sc = -10 },
{ .max_sc = 10 } };
num_t num_uc = { NUM_TYPE_UCHAR, &uc, "%u apples", { .min_sc = 0 },
{ .max_sc = UCHAR_MAX } };
num_t num_ss = { NUM_TYPE_SSHRT, &ss, "%d points", { .min_ss = -10 },
{ .max_ss = 10 } };
num_t num_us = { NUM_TYPE_USHRT, &us, "%u meters", { .min_ss = 0 },
{ .max_ss = USHRT_MAX } };
num_t num_si = { NUM_TYPE_SINT, &si, "%d dollars", { .min_si = -10 },
{ .max_si = 10 } };
num_t num_ui = { NUM_TYPE_UINT, &ui, "%u seconds", { .min_si = 0 },
{ .max_si = UINT_MAX } };
num_t num_sl = { NUM_TYPE_SLONG, &sl, "%d depth", { .min_sl = -10 },
{ .max_sl = 10 } };
num_t num_ul = { NUM_TYPE_ULONG, &ul, "%u km", { .min_sl = 0 },
{ .max_sl = ULONG_MAX } };
void
num_print(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
printf (num->fmt, *(signed char *)num->ptr);
} else if (num->type == NUM_TYPE_UCHAR) {
printf (num->fmt, *(unsigned char *)num->ptr);
} else if (num->type == NUM_TYPE_SSHRT) {
printf (num->fmt, *(signed short *)num->ptr);
} else if (num->type == NUM_TYPE_USHRT) {
printf (num->fmt, *(unsigned short *)num->ptr);
}
/* ... */
}
void
num_increase(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
signed char value = *(signed char *)num->ptr;
if (value < num->max.max_sc) {
*(signed char *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_UCHAR) {
unsigned char value = *(unsigned char *)num->ptr;
if (value < num->max.max_uc) {
*(unsigned char *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_SSHRT) {
signed short value = *(signed short *)num->ptr;
if (value < num->max.max_ss) {
*(signed short *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_USHRT) {
unsigned short value = *(unsigned short *)num->ptr;
if (value < num->max.max_us) {
*(unsigned short *)(num->ptr) = ++value;
}
}
/* ... */
}
void
num_decrease(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
signed char value = *(signed char *)num->ptr;
if (value > num->min.min_sc) {
*(signed char *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_UCHAR) {
unsigned char value = *(unsigned char *)num->ptr;
if (value > num->min.min_uc) {
*(unsigned char *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_SSHRT) {
signed short value = *(signed short *)num->ptr;
if (value > num->min.min_ss) {
*(signed short *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_USHRT) {
unsigned short value = *(unsigned short *)num->ptr;
if (value > num->min.min_us) {
*(unsigned short *)(num->ptr) = --value;
}
}
/* ... */
}
void
num_cpyvalue(num_t *dst, const num_t *src)
{
if (dst->type == NUM_TYPE_SCHAR) {
*(signed char *)dst->ptr = *(signed char *)src->ptr;
} else if (dst->type == NUM_TYPE_UCHAR) {
*(unsigned char *)dst->ptr = *(unsigned char *)src->ptr;
} else if (dst->type == NUM_TYPE_SSHRT) {
*(signed short *)dst->ptr = *(signed short *)src->ptr;
} else if (dst->type == NUM_TYPE_USHRT) {
*(unsigned short *)dst->ptr = *(unsigned short *)src->ptr;
}
/* ... */
}
void
num_change(num_t *num)
{
char c;
num_t num_new = *num;
signed char new_sc;
unsigned char new_uc;
signed short new_ss;
unsigned short new_us;
/* ... */
if (num->type == NUM_TYPE_SCHAR) {
new_sc = *(signed char *)num->ptr;
num_new.ptr = &new_sc;
} else if (num->type == NUM_TYPE_UCHAR) {
new_uc = *(unsigned char *)num->ptr;
num_new.ptr = &new_uc;
} else if (num->type == NUM_TYPE_SSHRT) {
new_ss = *(signed short *)num->ptr;
num_new.ptr = &new_ss;
} else if (num->type == NUM_TYPE_USHRT) {
new_us = *(unsigned short *)num->ptr;
num_new.ptr = &new_us;
}
printf("The value is: ");
num_print(num);
putchar('\n');
printf ("Press U/D/O: ");
do {
c = getchar();
if (c == '\n') {
continue;
} else if ((c == 'U') || (c == 'u')) {
num_increase (&num_new);
} else if ((c == 'D') || (c == 'd')) {
num_decrease (&num_new);
} else if ((c == 'O') || (c == 'o')) {
break;
}
printf("The value is: ");
num_print(&num_new);
putchar('\n');
printf ("Press U/D/O: ");
} while ((c != 'O') && (c != 'o'));
num_cpyvalue (num, &num_new);
}
int
main (int argc, char *argv[])
{
num_change (&num_sc);
printf ("The new value is: ");
num_print(&num_sc);
putchar('\n');
return 0;
}
int and long (ignoring long long), and their unsigned counterpart.
In one of my program, I have a lot of (about 200) numeric variables of
different types, signed and unsigned.
Now I want to create a generic function that shows the value of a
variable on the display with a format string dependent on the
variable, increase/decrease it inside a range dependent on the
variable and set it the new value.
I create the following code... do you have any suggestions or
improvements? It seems to me too complex to read (a lot of if(p-
type)... )
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
signed char sc = -1;
unsigned char uc = UCHAR_MAX;
signed short ss = -1;
unsigned short us = SHRT_MAX;
signed int si = -1;
unsigned int ui = UINT_MAX;
signed long int sl = -1;
unsigned long int ul = ULONG_MAX;
typedef struct {
enum {
NUM_TYPE_SCHAR,
NUM_TYPE_UCHAR,
NUM_TYPE_SSHRT,
NUM_TYPE_USHRT,
NUM_TYPE_SINT,
NUM_TYPE_UINT,
NUM_TYPE_SLONG,
NUM_TYPE_ULONG,
} type;
void *ptr;
const char *fmt;
union {
signed char min_sc;
unsigned char min_uc;
signed short min_ss;
unsigned short min_us;
signed int min_si;
unsigned int min_ui;
signed long min_sl;
unsigned long min_ul;
} min;
union {
signed char max_sc;
unsigned char max_uc;
signed short max_ss;
unsigned short max_us;
signed int max_si;
unsigned int max_ui;
signed long max_sl;
unsigned long max_ul;
} max;
} num_t;
/* Just some example variables */
num_t num_sc = { NUM_TYPE_SCHAR, &sc, "%d degrees", { .min_sc = -10 },
{ .max_sc = 10 } };
num_t num_uc = { NUM_TYPE_UCHAR, &uc, "%u apples", { .min_sc = 0 },
{ .max_sc = UCHAR_MAX } };
num_t num_ss = { NUM_TYPE_SSHRT, &ss, "%d points", { .min_ss = -10 },
{ .max_ss = 10 } };
num_t num_us = { NUM_TYPE_USHRT, &us, "%u meters", { .min_ss = 0 },
{ .max_ss = USHRT_MAX } };
num_t num_si = { NUM_TYPE_SINT, &si, "%d dollars", { .min_si = -10 },
{ .max_si = 10 } };
num_t num_ui = { NUM_TYPE_UINT, &ui, "%u seconds", { .min_si = 0 },
{ .max_si = UINT_MAX } };
num_t num_sl = { NUM_TYPE_SLONG, &sl, "%d depth", { .min_sl = -10 },
{ .max_sl = 10 } };
num_t num_ul = { NUM_TYPE_ULONG, &ul, "%u km", { .min_sl = 0 },
{ .max_sl = ULONG_MAX } };
void
num_print(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
printf (num->fmt, *(signed char *)num->ptr);
} else if (num->type == NUM_TYPE_UCHAR) {
printf (num->fmt, *(unsigned char *)num->ptr);
} else if (num->type == NUM_TYPE_SSHRT) {
printf (num->fmt, *(signed short *)num->ptr);
} else if (num->type == NUM_TYPE_USHRT) {
printf (num->fmt, *(unsigned short *)num->ptr);
}
/* ... */
}
void
num_increase(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
signed char value = *(signed char *)num->ptr;
if (value < num->max.max_sc) {
*(signed char *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_UCHAR) {
unsigned char value = *(unsigned char *)num->ptr;
if (value < num->max.max_uc) {
*(unsigned char *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_SSHRT) {
signed short value = *(signed short *)num->ptr;
if (value < num->max.max_ss) {
*(signed short *)(num->ptr) = ++value;
}
} else if (num->type == NUM_TYPE_USHRT) {
unsigned short value = *(unsigned short *)num->ptr;
if (value < num->max.max_us) {
*(unsigned short *)(num->ptr) = ++value;
}
}
/* ... */
}
void
num_decrease(num_t *num)
{
if (num->type == NUM_TYPE_SCHAR) {
signed char value = *(signed char *)num->ptr;
if (value > num->min.min_sc) {
*(signed char *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_UCHAR) {
unsigned char value = *(unsigned char *)num->ptr;
if (value > num->min.min_uc) {
*(unsigned char *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_SSHRT) {
signed short value = *(signed short *)num->ptr;
if (value > num->min.min_ss) {
*(signed short *)(num->ptr) = --value;
}
} else if (num->type == NUM_TYPE_USHRT) {
unsigned short value = *(unsigned short *)num->ptr;
if (value > num->min.min_us) {
*(unsigned short *)(num->ptr) = --value;
}
}
/* ... */
}
void
num_cpyvalue(num_t *dst, const num_t *src)
{
if (dst->type == NUM_TYPE_SCHAR) {
*(signed char *)dst->ptr = *(signed char *)src->ptr;
} else if (dst->type == NUM_TYPE_UCHAR) {
*(unsigned char *)dst->ptr = *(unsigned char *)src->ptr;
} else if (dst->type == NUM_TYPE_SSHRT) {
*(signed short *)dst->ptr = *(signed short *)src->ptr;
} else if (dst->type == NUM_TYPE_USHRT) {
*(unsigned short *)dst->ptr = *(unsigned short *)src->ptr;
}
/* ... */
}
void
num_change(num_t *num)
{
char c;
num_t num_new = *num;
signed char new_sc;
unsigned char new_uc;
signed short new_ss;
unsigned short new_us;
/* ... */
if (num->type == NUM_TYPE_SCHAR) {
new_sc = *(signed char *)num->ptr;
num_new.ptr = &new_sc;
} else if (num->type == NUM_TYPE_UCHAR) {
new_uc = *(unsigned char *)num->ptr;
num_new.ptr = &new_uc;
} else if (num->type == NUM_TYPE_SSHRT) {
new_ss = *(signed short *)num->ptr;
num_new.ptr = &new_ss;
} else if (num->type == NUM_TYPE_USHRT) {
new_us = *(unsigned short *)num->ptr;
num_new.ptr = &new_us;
}
printf("The value is: ");
num_print(num);
putchar('\n');
printf ("Press U/D/O: ");
do {
c = getchar();
if (c == '\n') {
continue;
} else if ((c == 'U') || (c == 'u')) {
num_increase (&num_new);
} else if ((c == 'D') || (c == 'd')) {
num_decrease (&num_new);
} else if ((c == 'O') || (c == 'o')) {
break;
}
printf("The value is: ");
num_print(&num_new);
putchar('\n');
printf ("Press U/D/O: ");
} while ((c != 'O') && (c != 'o'));
num_cpyvalue (num, &num_new);
}
int
main (int argc, char *argv[])
{
num_change (&num_sc);
printf ("The new value is: ");
num_print(&num_sc);
putchar('\n');
return 0;
}