Plz clarify,
Thanks,
Ram
We typedef system dependent types for portability. E.g. a system
specific integer type WD_LONG.
We do typedef WD_LONG splong;
splong x;
/* ...*/
When we want to migrate our code to another system we change the typedef
to that system's specific type or to another type.
E.g.
The line typedef WD_LONG splong;
becomes typedef WORD splong;
splong x;
/* ... */
where WORD is the equivallent system specific type of the new system.
Ioannis
--
* Ioannis Vranos
* Programming pages: http://www.noicys.f2s.com
* Alternative URL: http://run.to/noicys
size_t is unsigned on some systems, long unsigned on others.
There're a few others like that.
--
pete
long is never unsigned.
Are you sure about that. These are defined in a draft I have.
- minimum value for an object of type long int
LONG_MIN -2147483647
- maximum value for an object of type long int
LONG_MAX +2147483647
- maximum value for an object of type unsigned long int
ULONG_MAX 4294967295
John
I think you misinterpreted Pete. He didn't say "long is unsigned", he said
size_t is "long unsigned". The two modifiers "long" and "unsigned" may be
specified in any order; "long unsigned var;" or "unsigned long var;" are
both correct.
Pete is correct to say that on some systems size_t is unsigned int, and on
some others, size_t is unsigned long int.
--
Simon.
Huh? I use a lot of unsigned longs, and I especially like them
for bitwise flags ... don't you?
Any girls around again, Ioannis?
willem
He said "long is never unsigned" which is true. long and signed long are
the same. Why he said that is another thing, but I'm guessing he did not
know unsigned long is the same as long unsigned (which was news to me
too btw).
> long is never unsigned.
Ioannis...
You might want to do a little research on that.
--
Morris Dovey
West Des Moines, Iowa USA
One of the benefits of a typedef can be significantly improved
readability. Consider three functions:
The first takes several int and float parameters and returns a
pointer to a 2d array of int, int(*)[5][10].
The second takes a different set of int and float parameters and
returns a pointer to a 2d array of int, int(*)[10][6].
The third takes a pointer to one of each of these functions and
returns a pointer to a 2d array of int, int(*)[5][6].
The declaration for each is
int (*f1(int, int, float, float, ..., int))[5][10]; /*not varadic,*/
int (*f2(int, float, float, ..., int))[10][6]; /*just lazy*/
int (*f3(int(*(*)(int,int,float,float,...,int))[5][10],
int(*(*)(int,float,float,...,int))[10][6]))[5][6];
With typedef:
typedef int (*f1_t(. . . ))[5][10];
typedef int (*f2_t(. . .))[10][6];
the declaration for the third function becomes
int (*f3(f1_t *, f2_t *))[5][6];
Its possibly even worse when a function returns a pointer to another
function. Let g be a function that takes three pointers to char and
returns a pointer to a function similar to strcmp. The declaration
would be
int(*g(char*,char*,char*))(const char*, const char*);
With typedef:
int strcmp_t(const char*, const char*);
the declaration becomes
strcmp_t * g(char*, char*, char*);
<<Remove the del for email>>
(I think it would help to give some examples.)
>Why data types are type defined. other than for better documentation
>is there any other reason ?. I did not understand when ritchie says
>they are for portability. what does ritchie mean by that.
Presumably (as others noted) this refers to things like size_t and
ptrdiff_t (ANSI C types) and off_t (POSIX, not ANSI) and so on.
To really answer the question, though, we have to look at what
typedef *does*.
The obvious thing for typedef to do is just what its name says,
"define a new type", but unfortunately, that is exactly what it
fails to do. :-) Instead, it makes an alias -- a new name -- for
some old, existing type.
The typedef keyword acts, syntactically speaking, as if it were a
storage-class specifier, like "register", "auto", and "static"
(ignoring than the weird new C99 use for "static" in array sizes
in function parameters). Thus, since you might properly write:
register int i, j;
static double k, *l;
auto struct gronk *m, **n;
in various places, you can replace "register", "static", or "auto"
with "typedef", and write:
typedef union blergh o, *p, **q;
This changes what would ordinarily be three variable declarations
(for o, p, and q) into three type-alias declarations. The types
that are being aliased -- "union blergh" for o, "union blergh *"
for p, and "union o **" for q -- already exist; typedef just gives
you an extra, and often shorter, name for each of them.
So, now the question becomes:
Why would you define a new, sometimes shorter, name for an
old existing type?
and there are in fact many possible answers, including the really
obvious one, "the existing name is really long and I am too lazy
to write it out". :-)
A less-obvious one is that you might choose to use *different*
types, on different machines, to store the same "kind" (in some
fundamental sense) of information. The "size_t" type from the
various <stdwhatever.h> files is an example of this. C requires,
fundamentally, that all objects be made up of a set of "C bytes"
("unsigned char"s, really -- they may be larger than the machine's
"hardware bytes" if needed). This in turn implies that you can
measure the number of "C bytes" in any object, including compound
objects like arrays, using some nonnegative[%] integer. But what
integer type is large enough to hold such a size? On the PDP-11,
"unsigned int" will suffice, but on the DEC/Compaq Alpha, you need
"unsigned long".
[% One can even say "positive" because zero-byte objects are
prohibited, although I think that was a mistake.]
Thus, though the underlying type (unsigned int, or unsigned long)
may differ, the alias "size_t" will always get you a type that is
big enough to hold all possible "sizeof" values. This does, however,
expose a flaw in the plan: if size_t is some unknown, machine-dependent
type, how will you print such a value with printf()? The right
format is "%u" on the PDP-11 but "%lu" on the Alpha.
There are techniques for getting around this as well (see the C99
standard for some of the more complicated ones), but it shows some
of the problems with information-hiding -- which, indeed, is what
this is: hiding the implementation details and exposing only the
typedef, and any other things you decide you need to expose about
it in order for programmers to use it properly. Information-hiding
is in turn a part of abstraction, which is in a way what programming
is all about.
When it comes to hiding information and doing abstraction, however,
typedefs in C have what I consider a fundamental flaw. Remember that
typedef never defines a new type, just a new name for an existing
type. Quite often, this will wind up being a "struct", because you
will want to hold on to a number of values of various types, all in
one group. Modern languages that provide this sort of abstraction
usually throw "functions that operate on such objects" into the mix
as well, and call this something like a "class"; and indeed, the
closest thing C has to a C++ class is the struct, so this sort of
abstraction virtually always involves defining some set of structs.
The obvious question is: "so what?" Well, remember that structs
often *require* tags -- any time you are going to use forward
references, such as linked lists, you need a tag -- so you might as
well just always use tags. That means you will always be writing:
struct s {
struct s *next;
... more contents here ...
};
If you want to typedef these, you can do this:
typedef struct s somealias; /* refer to the incomplete type */
struct sometag {
somealias *next; /* can do this because we put typedef first */
... more contents here ...
};
but now it is clear that the alias is just an alias for "struct s",
and you could just expand it in place every time:
struct s {
struct s *next;
... more contents here ...
};
You can (and I say "should") use the same name for the tag as for
the alias, which saves mental effort and tends to improve, or at
least not harm, readability; so that means the alias merely saves
you from typing the word "struct".
Because of this, I find typedefs for structures almost (though not
quite entirely) useless. Just write "struct blah *p" instead of
"blah *p". You can even make a structure that contains only a
single ordinary type like "int" or "double" or whatever -- and
doing so induces automatic compiler type-checking that "typedef"
would not -- so "struct" can be considered *the* type abstraction
mechanism in C.
The nice thing about using the struct keyword is that it avoids
"namespace pollution". A name after a struct keyword is always a
structure tag, and is thus always in the "tag namespace". This is
quite different from typedef identifiers, which are in the "ordinary
identifier" namespace. This makes for potential name clashes,
which is what leads some programmers to use special conventions
for typedef names, such as the "_t" suffixes for POSIX:
pthread_t
pthread_key_t
pthread_attr_t
pthread_cond_t
pthread_mutex_t
and so on. (POSIX lays claim on "*_t", more or less, so any ANSI-C
programmer who intends to use POSIX as a supplemental standard
might be wise to leave this suffix to POSIX, and come up with yet
another convention.) I think the easiest answer is to avoid the
problem entirely, by writing out the word "struct". In effect,
the word "struct" means "the user-defined abstract type whose name
is...". Hence, I say that the keyword "struct" is really just a
funny acronym: STRange spelling for User-defined abstraCt Type.
In short, my answer to "what are typedefs for" is "very little:
use them as sparingly as possible; use struct for abstraction
instead, as much as possible."
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
El Cerrito, CA, USA Domain: to...@bsdi.com +1 510 234 3167
http://claw.eng.bsdi.com/torek/ (not always up) I report spam to abuse@.
"nos...@elf.eng.bsdi.com" *is* my address (one of many actually).
I saw a lot of anger around here ( :) ) so what i said is that the type
long is always signed, that is
long is always equivallent with signed long. The original poster however
meant that size_t sometimes is unsigned (=unsigned int), and sometimes
unsigned long. He is right on that, but a size_t can be a whatever
unsigned integer type (e.g. unsigned short).
> The two modifiers "long" and "unsigned" may be
> specified in any order; "long unsigned var;" or "unsigned long var;"
Calling them "long unsigned" helps me remember %lu instead of %ul
--
pete
No, you saw no anger. All you saw was the usual exasperation. This time,
for once, I don't think it was your fault.
> so what i said is that the type
> long is always signed, that is
Yes, you're right:
long num = 0; /* num is signed */
But, of course, this is also valid, as you know:
unsigned long othernum = 0;
>
> long is always equivallent with signed long. The original poster however
> meant that size_t sometimes is unsigned (=unsigned int), and sometimes
> unsigned long. He is right on that, but a size_t can be a whatever
> unsigned integer type (e.g. unsigned short).
Correct.
--
Richard Heathfield : bin...@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Anger is a strong word - I don't think that's what you saw.
>long is never unsigned.
I take 'long' to be the type that can have qualifiers, unsigned or signed.
Your intention is clear now though, long without a qualifier is never
unsigned.
Apologies if offence was perceived.
John
>Hi,
> In typedefs, we commonly come across type definitions of data types
>in header files.
>Why data types are type defined. other than for better documentation
>is there any other reason ?.
If you mean types like size_t in system headers then this allows each
implementation to select the type that it most appropriate for it.
In user defined headers that is also true and it keep the type definition
in one place which makes it much easier to change should that be necessary.
>I did not understand when ritchie says
>they are for portability. what does ritchie mean by that.
For system headers it hides implementation details from the program code
which means that the program code is not dependent on implementation
details (or at least less so) which makes it more portable.
--
-----------------------------------------
Lawrence Kirby | fr...@genesis.demon.co.uk
Wilts, England | 7073...@compuserve.com
-----------------------------------------
That last one should read:
"union blergh **" for q
of course.