[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

A generic interface for numeric variables

pozz

4/4/2011 3:39:00 PM

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-
>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;
}
11 Answers

ram

4/9/2011 12:15:00 AM

0

pozz <pozzugno@gmail.com> writes:
>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.

You have invented run-time types / classes / late-binding!

So you can use any of the means to implement OOP in C,
such as

http://google.to/search?...

. However, in C, it seems a little bit sad that the compiler
knows the type so that this could be done statically via
function overloads, but C does not offer this. Otherwise,
one would be able to define

void print( int ...
void print( char ...
void printf( double ...

.

Bartc

4/9/2011 10:10:00 AM

0

"pozz" <pozzugno@gmail.com> wrote in message
news:277ccf24-f849-46e1-ab6e-4574007503a9@s9g2000yqm.googlegroups.com...
> 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.

You say (elsewhere) that these are in a different module that you can't
change?

How many type combinations are there in all? (You say in yet another post
that you are only presenting a small part of the overall problem.)

> 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;

Declare the enum stuff separately. That then suggests the type tag names can
be used anywhere, rather than belonging to 'num_t'.

From your other examples, it seems the lower/upper limits can be different
for every variable, rather than every type.

> /* 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);
> }
> /* ... */
> }

That should be a switch statement here, rather than a chain of
if-statements.

But in any case, there seems to much code going on, when you could be using
tables.

To summarise, you have:

* About 200 variables somewhere in your program
* You know, statically, the addresses and types of these variables
* Each variable can be 1, 2, 4 or 8 bytes, and can be signed or unsigned
* Each variable can have an upper and lower limit, expressed as the same
type as the variable

This suggests you might have a 200-entry table for the variables, but it's
not clear how these variables are used in your project. If there are
variables, x, y, and z, would it be feasible to create corresponding indices
x_num, y_num, and z_num, which are used to fetch info from the table.

For printing values, you can use a table of format strings, indexed by the
type tag of a variable.

For extracting the value of a variable, you need a function that takes a
variable index, and expands it's value (1, 2, 4 or 8 bytes, signed or
unsigned) to 8 bytes, if that is the maximum width. (If the majority of your
variables are smaller, then can be inefficient, if your processor is
16-bits.)

And for updating a variable, the same sort of thing. In other words, use a
pair get/set functions:

setvariable(var_index, x);
x = getvariable(var_index);

Where x must be the largest width in use. I don't think it matters whether x
is signed or unsigned.

Limit checks can be done inside the set-function, or elsewhere.

An increment function might look like:

void increment(int v){
unsigned long x;
x=get_variable(v);
if (x<varupper[v]) set_variable(x+1);
}

If some limits are in between max of signed long, and max of unsigned long,
or some upper limits are negative, then you need to treat signed/unsigned
values differently here. However, if the limit check is built-in to
set_variable (which will itself deal with signedness), then increment can be
just:

set_variable(v,get_variable(v)+1);

Copying one variable to another can be done using set/get, or, if
compatible, using memcpy, using a table of sizes (1 to 8 bytes), indexed by
the variable's type tag.

Alternatively, if there are really only 8 type combinations, you can just
have 8 lots of functions! This would be simplest, and likely fastest.
However this business of every variable having customised upper/lower limits
doesn't quite comfortably into such a scheme; possibly I've misunderstood
that.

--
Bartc

pozz

4/9/2011 1:26:00 PM

0

Il 09/04/2011 12:10, BartC ha scritto:
>> 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.
>
> You say (elsewhere) that these are in a different module that you can't
> change?

Definetely yes. Someone else wrote some code in the past with several
variables of different types and exposed them through extern keyword in
a .h file.
My goal is to create some functions that show the numeric values on a
display, let the user to change the values (inside a range) and set the
new values.


> How many type combinations are there in all? (You say in yet another
> post that you are only presenting a small part of the overall problem.)

Combinations? Each variable can be signed/unsigned char/short/int/long.
So there are 8 different variable types.
In general, each variable has an associated range. There are many
variables with the same limits (enable/disable variables, so the limits
are 0-1), but it is not true for all.

>>[...]
>> 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);
>> }
>> /* ... */
>> }
>
> That should be a switch statement here, rather than a chain of
> if-statements.

In the past I wrote several articles that pointed how inefficient are
switche statement respect a chain of if-statements. Anyway, this isn't
important for my problem.


> To summarise, you have:
>
> * About 200 variables somewhere in your program
> * You know, statically, the addresses and types of these variables
> * Each variable can be 1, 2, 4 or 8 bytes, and can be signed or unsigned
> * Each variable can have an upper and lower limit, expressed as the same
> type as the variable

The code should be portable on a 16-bit machine and a 32-bit machine. So
the size of variables may vary: int is 16-bits large for 16-bit machine
and 32-bit large for 32-bit machine.
Long are 32-bits large for both machines, so I don't have at the moment
8-bytes variables.

The limits aren't already defined in the actual code, so I can decide to
use the same type of the variable they refer or not.


> This suggests you might have a 200-entry table for the variables, but
> it's not clear how these variables are used in your project. If there
> are variables, x, y, and z, would it be feasible to create corresponding
> indices x_num, y_num, and z_num, which are used to fetch info from the
> table.
>
> For printing values, you can use a table of format strings, indexed by
> the type tag of a variable.
>
> For extracting the value of a variable, you need a function that takes a
> variable index, and expands it's value (1, 2, 4 or 8 bytes, signed or
> unsigned) to 8 bytes, if that is the maximum width. (If the majority of
> your variables are smaller, then can be inefficient, if your processor
> is 16-bits.)
>
> And for updating a variable, the same sort of thing. In other words, use
> a pair get/set functions:
>
> setvariable(var_index, x);
> x = getvariable(var_index);
>
> Where x must be the largest width in use. I don't think it matters
> whether x is signed or unsigned.

So you propose something similar to (suppose 3 variables instead of 200):
#define X_NUM 0
#define Y_NUM 1
#define Z_NUM 2

/* Variables defined in some other modules */
extern int x;
extern unsigned char y;
extern unsigned long z;

long getvariable(int var_index) {
switch(var_index) {
case X_NUM:
return x;
case Y_NUM:
return y;
case Z_NUM:
return z;
}
}
I think getvariable() can't be used for signed and unsigned long
variables. If z above is very big (greater than LONG_MAX), the return
value of getvariable() could be wrong.


> Limit checks can be done inside the set-function, or elsewhere.
>
> An increment function might look like:
>
> void increment(int v){
> unsigned long x;
> x=get_variable(v);
> if (x<varupper[v]) set_variable(x+1);
> }
>
> If some limits are in between max of signed long, and max of unsigned
> long, or some upper limits are negative, then you need to treat
> signed/unsigned values differently here. However, if the limit check is
> built-in to set_variable (which will itself deal with signedness), then
> increment can be just:
>
> set_variable(v,get_variable(v)+1);
>
> Copying one variable to another can be done using set/get, or, if
> compatible, using memcpy, using a table of sizes (1 to 8 bytes), indexed
> by the variable's type tag.
>
> Alternatively, if there are really only 8 type combinations, you can
> just have 8 lots of functions! This would be simplest, and likely
> fastest. However this business of every variable having customised
> upper/lower limits doesn't quite comfortably into such a scheme;
> possibly I've misunderstood that.

Thank you for your suggestions.

Bartc

4/9/2011 2:40:00 PM

0



"pozz" <pozzugno@gmail.com> wrote in message
news:inpmob$37s$1@nnrp.ngi.it...
> Il 09/04/2011 12:10, BartC ha scritto:

>> That should be a switch statement here, rather than a chain of
>> if-statements.
>
> In the past I wrote several articles that pointed how inefficient are
> switche statement respect a chain of if-statements. Anyway, this isn't
> important for my problem.

A switch ought to be just a range check, and an indirect jump. The
if-version in this case is 1 to 8 comparisons, each followed by a direct
jump.

If you stay with 'if', then just check for the mostly common types near the
top.

>> For extracting the value of a variable, you need a function that takes a
>> variable index, and expands it's value (1, 2, 4 or 8 bytes, signed or
>> unsigned) to 8 bytes, if that is the maximum width. (If the majority of
>> your variables are smaller, then can be inefficient, if your processor
>> is 16-bits.)
>>
>> And for updating a variable, the same sort of thing. In other words, use
>> a pair get/set functions:
>>
>> setvariable(var_index, x);
>> x = getvariable(var_index);
>>
>> Where x must be the largest width in use. I don't think it matters
>> whether x is signed or unsigned.
>
> So you propose something similar to (suppose 3 variables instead of 200):
> #define X_NUM 0
> #define Y_NUM 1
> #define Z_NUM 2

Yes. Or you can forget the table, and pass extra information to these
functions as needed:

a = getvariable(&x,NUM_TYPE_UCHAR)

That's more flexible, but not as tidy.

> /* Variables defined in some other modules */
> extern int x;
> extern unsigned char y;
> extern unsigned long z;
>
> long getvariable(int var_index) {
> switch(var_index) {
> case X_NUM:
> return x;
> case Y_NUM:
> return y;
> case Z_NUM:
> return z;
> }
> }

It would work more like this:

signed long getvariable(int var_index) {
switch (var_type_table[var_index]) {
case NUM_TYPE_UCHAR:
return (unsigned long) *(unsigned char*)(var_addr_table[var_index])
...

Or, not using a variable table, but supplying data as needed:

signed long getvariable(void* var_addr, int var_type) {
switch (var_type) {
case NUM_TYPE_UCHAR:
return (usigned long) *(unsigned char*)var_addr;
....
> I think getvariable() can't be used for signed and unsigned long
> variables. If z above is very big (greater than LONG_MAX), the return
> value of getvariable() could be wrong.

You mean, when 'long' is signed? It probably doesn't matter, the correct bit
pattern will be returned (usually a signed type can contain the bit pattern
of an unsigned version, and vice versa).

However if you use 'getvariable()' directly in an expression with mixed
signed types, then the return type of getvariable() could affect the result.
So you either cast the result of getvariable(), or have signed/unsigned
versions (but this means supplying information that is already known, in the
variable table, or in the variable type).

This is all a consequence of the fact that there is no one type that can
contain all values, signed and unsigned (signed long long int might be such
a type, but is not really feasible on your processor).

--
Bartc

pozz

4/10/2011 8:36:00 AM

0

Il 09/04/2011 16:39, BartC ha scritto:
> You mean, when 'long' is signed? It probably doesn't matter, the correct
> bit
> pattern will be returned (usually a signed type can contain the bit pattern
> of an unsigned version, and vice versa).

I knew C standard doesn't guarantee to maintain a correct value after
signed->unsigned->signed or unsigned->signed->unsigned.

Bartc

4/10/2011 6:52:00 PM

0



"pozz" <pozzugno@gmail.com> wrote in message
news:inrq6b$4r1$1@nnrp.ngi.it...
> Il 09/04/2011 16:39, BartC ha scritto:
>> You mean, when 'long' is signed? It probably doesn't matter, the correct
>> bit
>> pattern will be returned (usually a signed type can contain the bit
>> pattern
>> of an unsigned version, and vice versa).
>
> I knew C standard doesn't guarantee to maintain a correct value after
> signed->unsigned->signed or unsigned->signed->unsigned.

If that's really the case (which I don't quite believe, but perhaps it
depends on how the conversion is done), then you may need signed and
unsigned versions of every relevant function. (Which is not that different
from my suggestion to use a dedicated set of functions for each type...)

To convert signed to unsigned without conversion losses, I think there are
ways to do this, even if it means using memcpy. But then, you probably need
to worry about a signed representation using padding bits in different
positions, and different numbers, from unsigned ones, if you take the C
standard seriously.

--
Bartc



Keith Thompson

4/10/2011 7:23:00 PM

0

"BartC" <bc@freeuk.com> writes:
> "pozz" <pozzugno@gmail.com> wrote in message
> news:inrq6b$4r1$1@nnrp.ngi.it...
>> Il 09/04/2011 16:39, BartC ha scritto:
>>> You mean, when 'long' is signed? It probably doesn't matter, the correct
>>> bit
>>> pattern will be returned (usually a signed type can contain the bit
>>> pattern
>>> of an unsigned version, and vice versa).
>>
>> I knew C standard doesn't guarantee to maintain a correct value after
>> signed->unsigned->signed or unsigned->signed->unsigned.
>
> If that's really the case (which I don't quite believe, but perhaps it
> depends on how the conversion is done), then you may need signed and
> unsigned versions of every relevant function. (Which is not that different
> from my suggestion to use a dedicated set of functions for each type...)

Why don't you believe it? Can you cite anything in the standard
that makes such a guarantee?

See in particular C99 6.3.1.3, which says that the result of
conversion to a signed type is implementation-defined if the
value can't be represented. Why can't the implementation define
the conversion in such a way that round-trip conversions lose
information?

(Most implementations don't, but then most implementations use
2's-complement and don't have padding bits or trap representations.)

> To convert signed to unsigned without conversion losses, I think there are
> ways to do this, even if it means using memcpy. But then, you probably need
> to worry about a signed representation using padding bits in different
> positions, and different numbers, from unsigned ones, if you take the C
> standard seriously.

And trap representations, and 2's-complement vs. 1s'-complement
vs. sign-and-magnitude.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Bartc

4/10/2011 9:21:00 PM

0



"Keith Thompson" <kst-u@mib.org> wrote in message
news:ln4o656hd0.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:
>> "pozz" <pozzugno@gmail.com> wrote in message
>> news:inrq6b$4r1$1@nnrp.ngi.it...
>>> Il 09/04/2011 16:39, BartC ha scritto:
>>>> You mean, when 'long' is signed? It probably doesn't matter, the
>>>> correct
>>>> bit
>>>> pattern will be returned (usually a signed type can contain the bit
>>>> pattern
>>>> of an unsigned version, and vice versa).
>>>
>>> I knew C standard doesn't guarantee to maintain a correct value after
>>> signed->unsigned->signed or unsigned->signed->unsigned.
>>
>> If that's really the case (which I don't quite believe, but perhaps it
>> depends on how the conversion is done), then you may need signed and
>> unsigned versions of every relevant function. (Which is not that
>> different
>> from my suggestion to use a dedicated set of functions for each type...)
>
> Why don't you believe it? Can you cite anything in the standard
> that makes such a guarantee?
>
> See in particular C99 6.3.1.3, which says that the result of
> conversion to a signed type is implementation-defined if the
> value can't be represented. Why can't the implementation define
> the conversion in such a way that round-trip conversions lose
> information?

We are not interested in doing an actual conversion, such as
representing -27 as an unsigned value. Just in copying a particular set of,
say, 32-bits (of any type), into the 32-bits available to an unsigned int
type, for example.

If it is possible to independently read and write any bit of a 32-bit value
(signed or unsigned), then this should be possible. I suppose it is possible
that a particular pattern in the destination may be a trap representation,
such that, even if no arithmetic is performed, it's not practical to move
such a value around, or extract the original pattern.

But then, it is necessary to ask whether it makes sense to rule out a
straightforward implementation of a project, in favour of a complex one, for
the sake of a hardware that likely is never going to be encountered
(acknowledging that with the embedded hardware used here, the probability is
higher than normal).

--
Bartc

Keith Thompson

4/11/2011 2:07:00 AM

0

"BartC" <bc@freeuk.com> writes:
> "Keith Thompson" <kst-u@mib.org> wrote in message
> news:ln4o656hd0.fsf@nuthaus.mib.org...
>> "BartC" <bc@freeuk.com> writes:
>>> "pozz" <pozzugno@gmail.com> wrote in message
>>> news:inrq6b$4r1$1@nnrp.ngi.it...
>>>> Il 09/04/2011 16:39, BartC ha scritto:
>>>>> You mean, when 'long' is signed? It probably doesn't matter, the
>>>>> correct
>>>>> bit
>>>>> pattern will be returned (usually a signed type can contain the bit
>>>>> pattern
>>>>> of an unsigned version, and vice versa).
>>>>
>>>> I knew C standard doesn't guarantee to maintain a correct value after
>>>> signed->unsigned->signed or unsigned->signed->unsigned.
>>>
>>> If that's really the case (which I don't quite believe, but perhaps it
>>> depends on how the conversion is done), then you may need signed and
>>> unsigned versions of every relevant function. (Which is not that
>>> different
>>> from my suggestion to use a dedicated set of functions for each type...)
>>
>> Why don't you believe it? Can you cite anything in the standard
>> that makes such a guarantee?
>>
>> See in particular C99 6.3.1.3, which says that the result of
>> conversion to a signed type is implementation-defined if the
>> value can't be represented. Why can't the implementation define
>> the conversion in such a way that round-trip conversions lose
>> information?
>
> We are not interested in doing an actual conversion, such as
> representing -27 as an unsigned value. Just in copying a particular set of,
> say, 32-bits (of any type), into the 32-bits available to an unsigned int
> type, for example.
>
> If it is possible to independently read and write any bit of a 32-bit value
> (signed or unsigned), then this should be possible. I suppose it is possible
> that a particular pattern in the destination may be a trap representation,
> such that, even if no arithmetic is performed, it's not practical to move
> such a value around, or extract the original pattern.
>
> But then, it is necessary to ask whether it makes sense to rule out a
> straightforward implementation of a project, in favour of a complex one, for
> the sake of a hardware that likely is never going to be encountered
> (acknowledging that with the embedded hardware used here, the probability is
> higher than normal).

Then you're relying on things that the Standard doesn't guarantee.

That's ok, and I'm not saying you shouldn't do it; it's likely
to work on any modern hosted system (though I can imagine that
changing in the future). But the issue was what the Standard does
or doesn't guarantee.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.ne...
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

pozz

4/11/2011 5:18:00 PM

0

Il 10/04/2011 23:20, BartC ha scritto:
> But then, it is necessary to ask whether it makes sense to rule out a
> straightforward implementation of a project, in favour of a complex one,
> for the sake of a hardware that likely is never going to be encountered
> (acknowledging that with the embedded hardware used here, the
> probability is higher than normal).

This is a big question without a real answer.

Many times I have to choose an algorithm, an approach, an implementation
that is good for portability (adherent to the C standard), but not
straightforward.

It'd be nice to have a list of C standard limitations with an associated
probability to encounter a C implementation that shows that limitation.

For example, what is the probability to have a C implementation that
shows a trap when unsigned->signed conversion is performed on values not
representable with a signed type? Or that lose the original unsigned
value after a two-steps conversion unsigned->signed->unsigned?

Or what is the probability to have a C implementation with negative
values representation different than 2's complement?

What is the probability to have padding bits with integer types?

....and so on...

With a list similar to this, I can choose to have a low or high risk of
portability issues when choosing an algorithm or another one.