Is it good to use char instead of int to save memory?

D

Dr Malcolm McLean

Can you give some specific examples of why unsigned int is better than
unsigned char when values are in the range 0-255? I know with respect
to performance and memory there can be a difference.
The main reason is that anyone reading your code will do a double
take, and say "unsigned char? What's going on here? Normally unsigned
chars are used for arbitrary bytes of data, but this looks like an
index/count/counter. Why has he chosen that data type?"
Eventually of course he'll figure it out, but every little bit of
difficulty adds to the cost of maintaining your code, in a
supercumulative manner. Two little bits of difficulty add more than
twice the cost of one little bit, because humans can tolerate a
certain amount of distraction and get overwhelmed by too much.
 
D

Dr Malcolm McLean

On an 8 bit uC with 128 bytes of SRAM, where char is 8 bit and int is 16
bit, yes char is what you're going to want to use. You would usually avoid
larger types for performance/memory reasons unless you really need an int.
Then use an int.
On such a machine a program than runs in 100 bytes of memory is
usually as useful and cost-ecffective as one that runs in 50.
However, yes, this would be a circumstance in which char for small
integers is appropriate. In fact on such compilers int is often, non-
conformingly, 8 bits and long is 16 bits.
 
E

Ersek, Laszlo

Dr Malcolm McLean said:
Veteran readers of comp.lang.c will have noticed a change in my
moniker. I'm Dr Malcolm McLean now.

I'm not a veteran reader but I did notice it. Congratulations! Do you
have a public, low-res research page?

(Sorry for being OT.)

lacos
 
S

spinoza1111

Malcolm!! Are congratulations in order, old fellow? Did you complete
your PhD? If so: my sincere compliments. If not, my best wishes.

Veteran readers of comp.lang.c will have noticed a change in my
moniker. I'm Dr Malcolm McLean now.[/QUOTE]

Congratulations. Some people here think that academic qualifications
aren't as important as subservience to management and backstabbing
coworkers. I don't.
 
I

Ian Collins

I have no idea what that statement means. Having 128 bytes of RAM and
running in 100 bytes are two different things -- one is normally data
memory, the other code memory. Processors with a few hundred bytes of
RAM typically have several kilobytes of non-volatile code memory.

The question for those processors isn't how small you can make the
program, but rather whether it fits at all and how much data it can
handle. Or the question is how expensive a processor do we need for a
given job?


This is at least one such non-conforming compiler, but most compilers
for 8-bit processors support ints and longs that are conforming in size.

Agreed, I don't think I've ever used a compiler for an 8 bit micro where
int wasn't a conforming size. Which is why 8 bit types are often used
for small integers or counters
 
S

spinoza1111

I only once did that in an astro program that held data
about several millions of stars, where each byte saved made a
huge difference.
In all other cases, dont do it.

By the end of the IBM 1401's useful life, I was "squozing" more and
more data into its 8K memory using an extrabit which was intended to
demarcate operands to get a 7 bit rather than 6 bit word.

A bit later, I acquired a Sinclair by post from Britain, plugged it
in, and it started to smoke (American power, British machine). After
the fire department left and the smoke had cleared, it still worked
and used storage most elegantly. It ran Basic in 2K.
 
T

Thad Smith

Dr said:
On such a machine a program than runs in 100 bytes of memory is
usually as useful and cost-ecffective as one that runs in 50.

I have no idea what that statement means. Having 128 bytes of RAM and running
in 100 bytes are two different things -- one is normally data memory, the other
code memory. Processors with a few hundred bytes of RAM typically have several
kilobytes of non-volatile code memory.

The question for those processors isn't how small you can make the program, but
rather whether it fits at all and how much data it can handle. Or the question
is how expensive a processor do we need for a given job?
However, yes, this would be a circumstance in which char for small
integers is appropriate. In fact on such compilers int is often, non-
conformingly, 8 bits and long is 16 bits.

This is at least one such non-conforming compiler, but most compilers for 8-bit
processors support ints and longs that are conforming in size.
 
D

Dr Malcolm McLean

I have no idea what that statement means.
You've got 128 bytes of memory in your chosen processor. The cost of a
program that requires 1 byte is the exactly the same as the cost of a
program that requires 128 bytes. The cost of a program that requires
129 bytes is significantly higher, because it demands a hardware
redesign.
Now if you need 50 variables you are comfortably within the limits of
your processor. There is no advantage to making them chars (50 bytes)
over and above makingthem ints (100 bytes).
 
D

dspfun

The question is related to embedded system where most of our types are
typdefed as

typedef unsigned long int U32;
typedef unsigned short int U16;
typedef unsigned char U8;

and so on.

In this scenario, for variables that we know will always have values
in the range 0-255, would you prefer using U8 or U32 ?

Which is preferrable with respects to:

1) Code readability.
2) Keeping it simple, i.e. minimizing risk for bugs.
3) Reducing the probablitity of casts.
4) Code maintenancability.
 
E

Ersek, Laszlo

The question is related to embedded system where most of our types are
typdefed as

typedef unsigned long int U32;
typedef unsigned short int U16;
typedef unsigned char U8;

and so on.

In this scenario, for variables that we know will always have values
in the range 0-255, would you prefer using U8 or U32 ?

Neither. I would prefer "unsigned". The above typedef's are there so you
can choose exact width integers. That is, the selection criterion is
width, for whatever reason.

In this case however, I assume, you want something that's fast,
unsigned, and covers [0..255]. On a C99 platform I would recommend
uint_fast8_t, a type required by C99 7.18.1.3 "Fastest minimum-width
integer types".

Anywhere else I would recommend "unsigned". In my opinion, the default
integer promotions reflect the fact that there is a "most natural" word
size for any given machine, and that the most useful default behavior
for anything narrower is to get promoted to this "most natural" word
size as soon as possible -- obviously for speed. Therefore, for
individual variables *in general*, I think it's wrong to fight this
"rule of thumb".

I hope people with actual knowledge on the origins of the default
integer promotions will enlighten us.

Returning to the typedefs you quoted, "unsigned int" may coincide with
U16 or U32. The point is, you don't care, you simply want the fastest
one (which might be even "U24", theoretically).

lacos
 
P

Prof Craver

I'm confident that one's mental abilities aren't judged by choice of
numeric data type in C. ^_^ Some people might, but for those people I
would recommend chilling out.

And yet, it matters enough that we routinely see bugs and even
gaping security holes because some coder has to look all l33t and
clever.

One baffling example is the format specifier bug: while these
sometimes
happen for more complex reasons, mostly it's some kid showing off that
he
knows he can substitute printf( string ) for printf( "%s", string ).

I think it's astonishing that one of our most common security holes
occurs
for no other reason than vanity. Buffer overflows result from
genuine
mistakes or hurried coders facing a ship date; SQL injection
vulnerabilities
are caused by the same. Cross-site scripting vulnerabilities result
from
the genuine difficulty of sanitizing user-supplied HTML code. They
all
happen for a good bad reason. Meanwhile, with some exceptions,
format
specifier bugs are just some kid being smart/stupid.

Another example is the XOR swap trick to save one extra variable/
register.
It makes you look all cool and K-rad until you use your swap macro to
swap array with array.

I run the underhanded C contest (underhanded.xcott.com), and the XOR
swap trick was used by a couple submissions to trigger an error under
exactly those circumstances.

--X
 
B

Ben Pfaff

Prof Craver said:
And yet, it matters enough that we routinely see bugs and even gaping
security holes because some coder has to look all l33t and clever.

One baffling example is the format specifier bug: while these
sometimes happen for more complex reasons, mostly it's some kid
showing off that he knows he can substitute printf( string ) for
printf( "%s", string ).

Really? This is not my experience. Please give an example.
 
L

Lew Pitcher

Really? This is not my experience. Please give an example.

I think that Prof Craver is suggesting something like

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if (argc > 2)
printf(argv[1]); /* maybe Bang! you're dead! */

return EXIT_SUCCESS;
}

where the program code uses an unedited string as the format string for a
printf() call. This will work successfully (the printf() will generate
proper printable results, and will return a valid returnvalue) most of the
time, *but* will fail (won't generate proper printable results, may cause a
program abend or other unrecoverable error, may cause printf() not to
return a valid returnvalue) if the string contains a valid print specifier
escape sequence.
 
B

Ben Pfaff

Lew Pitcher said:
Really? This is not my experience. Please give an example.

I think that Prof Craver is suggesting something like [...]
if (argc > 2)
printf(argv[1]); /* maybe Bang! you're dead! */
[...]

That's clearly the code that he's suggesting. What I want as an
example is a case where this was done because "some coder has to
look all l33t". In my experience it's just a mistake, not some
kind of weird misplaced pride.
 
J

jamm

Dr said:
On such a machine a program than runs in 100 bytes of memory is
usually as useful and cost-ecffective as one that runs in 50.
However, yes, this would be a circumstance in which char for small
integers is appropriate. In fact on such compilers int is often, non-
conformingly, 8 bits and long is 16 bits.

hmmm? I don't quite follow. Having written code for 8bit micros, one
frequently desires to do some logging or buffering. Thus every byte of RAM
counts. Also int/16 bit operations can require two 8 bit operations and so
take more clock cycles.
 
I

Ian Collins

The question is related to embedded system where most of our types are
typdefed as

typedef unsigned long int U32;
typedef unsigned short int U16;
typedef unsigned char U8;

and so on.

In this scenario, for variables that we know will always have values
in the range 0-255, would you prefer using U8 or U32 ?

The answer is still "it depends".

It may save space, it may not. That largely depends on the the CPU's
alignment requirements.

It my be faster, it may not. That largely depends on the the CPU's
register (whether shorter types have to be sign extended) and bus width.
 
F

Flash Gordon

Dr said:
You've got 128 bytes of memory in your chosen processor. The cost of a
program that requires 1 byte is the exactly the same as the cost of a
program that requires 128 bytes. The cost of a program that requires
129 bytes is significantly higher, because it demands a hardware
redesign.
Now if you need 50 variables you are comfortably within the limits of
your processor. There is no advantage to making them chars (50 bytes)
over and above makingthem ints (100 bytes).

Then you have a new requirement which needs another 29 bytes and your
shafted. This *does* happen, and I've been the one to tell the
management that what they thought was a simple and profitable mod would
actually mean major work. As far as I'm aware it meant the job had to be
turned down, so it cost the company money. It was not my code!

Also, on military projects it certainly used to be the case that there
was a written requirement for 50% free capacity specifically to allow
for later enhancements, because it is very common for things to be upgraded.

So if you are working on a very limited resource project, you do *not*
go wasting the resources!
 
D

Dr Malcolm McLean

Then you have a new requirement which needs another 29 bytes and your
shafted. This *does* happen, and I've been the one to tell the
management that what they thought was a simple and profitable mod would
actually mean major work. As far as I'm aware it meant the job had to be
turned down, so it cost the company money. It was not my code!

Also, on military projects it certainly used to be the case that there
was a written requirement for 50% free capacity specifically to allow
for later enhancements, because it is very common for things to be upgraded.

So if you are working on a very limited resource project, you do *not*
go wasting the resources!
Alternatively the new requirements could make some of those 8-bit ints
go over 255.
The rules of (micro) optimisation
a) Don't do it.
b) Don't do it yet.
 
N

Nick

Lew Pitcher said:
I think that Prof Craver is suggesting something like

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
if (argc > 2)
printf(argv[1]); /* maybe Bang! you're dead! */

return EXIT_SUCCESS;
}

where the program code uses an unedited string as the format string for a
printf() call. This will work successfully (the printf() will generate
proper printable results, and will return a valid returnvalue) most of the
time, *but* will fail (won't generate proper printable results, may cause a
program abend or other unrecoverable error, may cause printf() not to
return a valid returnvalue) if the string contains a valid print specifier
escape sequence.

I saw just the opposite yesterday - a Windows pop-up box which contained
a literal "%s" in it where you'd expect some more useful information.
 
M

Mark Hobley

Seebs said:
Never use char unless you mean it. If you just want a value, and don't
really care too much about its range, always use int.

I would create a macro USMALL in a header file, and then define your small
numbers using:

USMALL c;

On an computer types where using a char datatype is more efficient (such as
on IBM compatible computers) the header file would define USMALL as follows:

#define USMALL unsigned char

(ie an unsigned char would be used)

On a platform where this produces overheads, the header file would define
USMALL as follows:

#define USMALL unsigned int

This would enable your code to be used portably on both platform types.

Mark.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top