also, I've seen in many places C code that re-implements over and over
and over linked lists, is this a rite of passage or isn't there any
standard implementation of a linked list ?
There is no standard implementation, because different implementations
have different goals.
-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet...@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
C's CPAN is sometimes referred to as "the Internet". Unfortunately, a
lot of non-C stuff has managed to creep in, but the Internet remains a
tremendous resource for C programmers.
> if this is asking too much then maybe a list of commonly used
> libraries for C ? for both Linux and Windows, not necessarily(but
> hopefuly) portable ?
Quite a few such libraries exist. SDL is often mentioned in this kind of
context.
> also, I've seen in many places C code that re-implements over and over
> and over linked lists, is this a rite of passage or isn't there any
> standard implementation of a linked list ?
TMTOWTDI. For example, who owns the member data - the list itself, or
the user-programmer? That's a design decision, and some people will make
it one way, some another. Should there be a header node? Some people say
yes, others say no. Should the list be doubly-linked, or
singly-linked? That's probably a decision to be made on a
program-by-program, or even list-by-list, basis. So far, three design
decisions, all independent, giving you eight potential designs, any one
of which will be considered The Right Thing by at least some people. Now
add in all the other design decisions that I haven't even begun to
mention, and you can see how little chance there is of ever getting
enough people to agree on this to turn it into a Standard.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
I am trying to design and implement a standard container library
for C.
I report about it regularly in this newsgroup.
Hehehe, that made me chuckle. Thanks for the early morning [post-
coffee] laugh.
When I was a teen in the 90s I was a fan of PCGPE and SWAG. Though
SWAG was pascal related I found porting the algorithms to C to not be
that hard. Of course this was a tad pre-popular internet days so
these sort of resources were geared to be the sort of things you can
download off a BBS and then browse offline. If I recall for SWAG you
could download modules into a reader and then browse through the
various articles written for it (on all sorts of topics). It was a
dream for a starting programmer to have access to all sorts of code
even if it was at times poorly written and buggy... :-)
Tom
I think that's slightly mis-stated. With C, there are many
implementations at any given time, as opposed to perl, where there are
many implementations as it evolves but only one implementation at a
given time.
I have big hopes for clc's wiki, but any cpan-like proxy would have to
be sorted by implementor: dinkumware, gcc, Intel.
--
frank
But having a C library is *a lot* different from having something that
came down from c-pan.
--
frank
yes but the "CCAN" could at least have three different list library
packages (one for each design you mentioned). i dont think there is just
one list library in the cpan...
bye
But there are M implementations and N goals, where M >> N. :)
Yeah.
But since one of the most common goals is "I want it embedded in the
data structures I'm already using", it's probably reasonable. Also,
lists are super easy to implement.
I still remember, though, back in 1990 or so, really struggling to
implement lists once.
I suspect it will never meet the requirements for the stuff I work on
which needs linked lists, or most of the stuff I've done in the past
which needed them.
I don't need the complexities introduced by some of your design
decisions, such as your decision to make it so generic (I know exactly
what I need, and it will never need to swap to being a tree or hash or
whatever). I've got something far simpler which was debugged years ago
which has everything needed for what it is used for.
Other peoples requirements are not the same as mine! For a start, your
requirements are different!
> I report about it regularly in this newsgroup.
You are posting C code, so it's completely topical.
--
Flash Gordon
I suspect it will never meet the requirements for the stuff I work on
which needs linked lists, or most of the stuff I've done in the past
which needed them.
I don't need the complexities introduced by some of your design
decisions, such as your decision to make it so generic (I know exactly
what I need, and it will never need to swap to being a tree or hash or
whatever). I've got something far simpler which was debugged years ago
which has everything needed for what it is used for.
Other peoples requirements are not the same as mine! For a start, your
requirements are different!
> I report about it regularly in this newsgroup.
You are posting C code, so it's completely topical.
--
Flash Gordon
I suspect it will never meet the requirements for the stuff I work on
which needs linked lists, or most of the stuff I've done in the past
which needed them.
I don't need the complexities introduced by some of your design
decisions, such as your decision to make it so generic (I know exactly
what I need, and it will never need to swap to being a tree or hash or
whatever). I've got something far simpler which was debugged years ago
which has everything needed for what it is used for.
Other peoples requirements are not the same as mine! For a start, your
requirements are different!
> I report about it regularly in this newsgroup.
You are posting C code, so it's completely topical.
--
Flash Gordon
Also, the goal formula ``I want to implement it myself'' actually gives rise
to N unique goals, due to the multiple instantiation of the ``myself''
variable.
:)
>> I am trying to design and implement a standard container library
>> for C.
>
> I suspect it will never meet the requirements for the stuff I work on
> which needs linked lists, or most of the stuff I've done in the past
> which needed them.
>
But... you are not forced to use that. It is for people that want to
use linked lists without bothering to reinvent the wheel again.
> I don't need the complexities introduced by some of your design
> decisions, such as your decision to make it so generic (I know exactly
> what I need, and it will never need to swap to being a tree or hash or
> whatever).
OK. Then go onusing your lists. I mean, what I want is that newcomers
(and oldtimers) that do NOT feel like reimplementing a binary search
tree, or a double linked list from scratch can use a standard package
that is immediately usable, comes with source code, and can be adapted
at will.
> I've got something far simpler which was debugged years ago
> which has everything needed for what it is used for.
>
Fine with me.
I think you are missing the point. There were scores of container
libraries for C++ when the STL came along. Those who had their own
carried on using them, most of those who didn't, picked the STL. That's
how libraries become "standard": they exist and people start using them.
> I don't need the complexities introduced by some of your design
> decisions, such as your decision to make it so generic (I know exactly
> what I need, and it will never need to swap to being a tree or hash or
> whatever). I've got something far simpler which was debugged years ago
> which has everything needed for what it is used for.
I don't know whether Jacob will achieve this (within the bounds of
standard C), but being generic is one of the reasons behind the C++ STL.
The beauty of the STL design is most users never see the complexity
behind this, they just use the containers "as is". I fear C's inherent
transparency will make this hard for Jacob to achieve.
--
Ian Collins
There are, but as there are a number of different ways of doing
fundamental things, this sort of thing will tend to happen.
Take a "real" string library. There are at least two very different
design approaches here. In one the thing still looks like a C string
(it has the extra information held in memory "left" of the pointer). In
the other the pointer is to a structure.
The first is easier to pass to the existing library functions, but the
address can change when the size changes (and so keeping pointers to
strings around for a while is risky). If a normal string is passed to
the new functions horrible things will happen.
The second is just a bit fiddly to pass to the existing library
functions, but the address is unchanging so copies can hang around. If
you try to pass a normal string to the new functions the compiler will
object. Accessing the contents involves an additional indirection
compared with the first approach - costing small amounts of time and
memory.
It's far from clear to me which of these is "right". I've done the
latter, another contributor here the former.
Ditto there are two major ways (at least, again) to do generic
containers. Are they structures with a void pointer, or are they little
structures that can be embedded in your own?
But whichever you choose, the moment you build on this (say anywhere
that generates a string of unknown length - reading, character set
conversion, (de)compression etc) you then have a library to do that
which is dependent on the first, so you need one of these for each.
With, say, 4 major binary design decisions to be made, that gives you 16
implementations (and, of course, 16 sets of goals).
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk
> m wrote:
>> for the C language is there something like CPAN is for Perl ?
>
> C's CPAN is sometimes referred to as "the Internet". Unfortunately, a
> lot of non-C stuff has managed to creep in, but the Internet remains a
> tremendous resource for C programmers.
If we were doing it now though, a more distinctive name for use in
searches would be a good idea!
My proposal gives you both. If you declare the size of your
data to be sizeof(void *) you do not store anything in the library
container but a pointer. You manage the data and there are no copies.
If you declare the data size to be the size of your actual data,
it is the library that copies the data, and manages the memory.
Very simple to use.
Since source code is available you can use it for your own structures
as well.
Write the library for C90 and release it under LGPL and maybe I might
care about it.
If the library requires lcc-win32 extensions and is proprietary you
can keep it.
Tom
Totally agree - if not written in standard C (unfortunately that still
means C90 today) then most folks just won't want it
Nothing wrong with C90. Only thing I borrow from C99 is long long. I
think that VLA and mid-block declarations are bad coding practice.
I'd settle for his library being C99 though.
My suggestion that it be C90 was because I suspect it's being written
for his compiler which isn't 100% ISO compatible.
Tom
While VLAs have their obvious problems, I don't see how you can object
to something that shortens and clarifies code (mixed declarations and code).
--
Ian Collins
I really do not care about C90.
How can you use 64 bit integers in C90?
That is really a showstopper. I have #ifdefed most of C99 but
long long is very difficult to do without,specially in the
bitstring package. I would be forced to use 32 bit chunks
that slows down everything in 64 bit machines that are fairly
comon place today,and will be even more so in the future, when the
library is used.
You are living in the past.
> If the library requires lcc-win32 extensions and is proprietary you
> can keep it.
>
> Tom
Anyway if I would be you I would never touch anything done by that
jacob navia heretic...
It is certainly true that no C90 implementation is required to supply a
64-bit integer type, but there's nothing preventing an implementation
from doing so. Unfortunately, taking advantage of such provision
necessarily renders your code non-portable to implementations that don't
provide it - but that's true of long long int as well.
If you need portable 64-bit integers, you have no choice but to use (or
write, and then use) a "bignum" library. If you only need portability to
platforms boasting C99 implementations, however, then long long int will
do fine.
<snip>
If I were writing a bitstring package, I'd declare a typedef for
some unsigned integer type and write the code so that it doesn't
make any assumptions about the size of the type. It should work
(perhaps slowly) even if the typedef is unsigned char. Even assuming
a C99 implementation, this would let you use 32-bit integers if
64-bit integer operations happen to be particularly slow. And if
some future system provides a fast 128-bit integer type, you could
take advantage of it with a 1-line change.
(It would also give you easy C90 compatibility if you cared about
that.)
[tiresome sarcasm snipped]
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Using a bignum library to treat bitstring in 64 bit chunks would have
even worst performance than using 32 bit chunks!
I have isolated the parts that need 64 bit stuff, and will try a
portable solution, but for the time being I use long long.
> If you only need portability to
> platforms boasting C99 implementations, however, then long long int will
> do fine.
>
I need variable length structures, but I use code that will work both in
C99 and in C89. I have even avoided // comments!
> <snip>
>
> >>> also, I've seen in many places C code that re-implements over and over
> >>> and over linked lists, is this a rite of passage or isn't there any
> >>> standard implementation of a linked list ?
>
> >> There is no standard implementation, because different implementations
> >> have different goals.
>
> > But there are M implementations and N goals, where M >> N. :)
>
> Yeah.
>
> But since one of the most common goals is "I want it embedded in the
> data structures I'm already using", it's probably reasonable. Also,
> lists are super easy to implement.
>
> I still remember, though, back in 1990 or so, really struggling to
> implement lists once.
and I seem to have spent a significant fraction of my programming life
debugging other peoples' linked list implementations.
I liked the queue implementation that had the linking backwards.
Removing an item from the queue was o(n)
My thought when I first saw C++'s std::list was "I won't have to debug
a linked list ever again!"
--
After a couple of projects that I've done in scheme, after many years
of C (and assembler), I've come to the conclusion that even
*starting*
a program in C is an exercise in premature optimization.
(Andrew Reilly comp.lang.scheme)
Sure. (Please understand that, when I say "you", I very often mean the
generic form of the word, to mean "C programmers in general", and I was
doing so in the above paragraph.) As the implementor of a compiler, you
inevitably have a very different outlook from non-implementors.)
It is undoubtedly true that using a bignum library for 64-bit ints will
give you poorer performance than using native 64-bit ints (unless, I
suppose, the bignum library is clever enough to work out that if it has
64-bit ints available it can basically be nothing more than a wafer-thin
wrapper around them). Performance and portability are sometimes
conflicting constraints, and the balance between them is a trade-off.
Your trade-off will be different to mine, which will be different to
Keith's, which will be different to Seebs's, and so on.
> I have isolated the parts that need 64 bit stuff, and will try a
> portable solution, but for the time being I use long long.
Then that's part of your trade-off. You are sacrificing a relatively
small amount of portability for a relatively large performance gain, and
that's a perfectly sensible choice to make.
>> If you only need portability to platforms boasting C99
>> implementations, however, then long long int will do fine.
>
> I need variable length structures, but I use code that will work both in
> C99 and in C89. I have even avoided // comments!
That's pretty much what I do, although my "variable length structures"
are probably very different to yours.
Avoiding // comments sounds trivial, doesn't it? But there is a good
reason for doing it if your code routinely gets used with multiple
compilers. In C90, // is almost always a syntax error (and in the few
corner cases when it isn't, the code may well mean something different
in C99 anyway). Although many C90 implementations do offer // comments
as an extension, enabling that extension can involve turning off other
checks as well. For example, gcc either is or at least appears to be one
such. It may be due to my ignorance, of course, but in gcc I can only
suppress warnings about // comments by turning off other warnings too,
warnings which I don't want to lose. And in Microsoft Visual Studio, my
options are to turn on Microsoft extensions (same deal, I lose other
warnings I want to keep) or to use a #pragma, which is non-portable in
the sense that no other implementation is required to honour the meaning
I intend with that #pragma. So, for me, // comments are a no-no. That
doesn't mean that nobody can use them; but it does mean that I can't use
them - at least not yet - and other people in my situation will also
find that they cause problems.
And of course // comments aren't very robust in Usenet listings, because
of line-wrap - but that's really a meta-issue, which only affects people
who post C (or C++) code on Usenet.
Because it's too easy to bury declarations/initializations in code
making it harder to sort out if variables are properly initialized
[and to what]. I prefer code like
{
declarations;
initializations;
code;
}
I'm ok with things like
if (blah) {
int x;
x = some_struct->member;
// blah...
}
But I think declaring variables wherever is messy and shows a lack of
forethought/design [e.g. you're just making up variables mid thought
as opposed to fully thinking through your algorithm first].
Tom
Well for starters, quite a few C90 compilers support long long as a
non-standard extension. I was using them on all sorts of UNIX boxes
with cc's from the early 90s all the time. As I said it's one thing I
borrow from C99.
> That is really a showstopper. I have #ifdefed most of C99 but
> long long is very difficult to do without,specially in the
> bitstring package. I would be forced to use 32 bit chunks
> that slows down everything in 64 bit machines that are fairly
> comon place today,and will be even more so in the future, when the
> library is used.
>
> You are living in the past.
Um, when I see fully C99 compilers being common place I might agree
with you.
Tom
> On Jan 7, 4:31 pm, Ian Collins <ian-n...@hotmail.com> wrote:
<snip>
>> While VLAs have their obvious problems, I don't see how you can object
>> to something that shortens and clarifies code (mixed declarations and code).
>
> Because it's too easy to bury declarations/initializations in code
> making it harder to sort out if variables are properly initialized
> [and to what]. I prefer code like
>
> {
> declarations;
>
> initializations;
>
> code;
> }
>
> I'm ok with things like
>
> if (blah) {
> int x;
> x = some_struct->member;
> // blah...
> }
>
>
> But I think declaring variables wherever is messy and shows a lack of
> forethought/design [e.g. you're just making up variables mid thought
> as opposed to fully thinking through your algorithm first].
Them's fight'n words!
When I write in a language that permits such things, I design my code
and think about my algorithms just as carefully but I then clean it up
(to my mind) by moving declarations so that all names have as small a
scope as possible and so that (where possible) they are initialised in
the declaration. I accept that not everyone agrees that this makes
things clearer but it is style I like to use and to read when I find
it in other people's code. It is not due to "making up variables mid
thought"!
BTW, all you needed was a "sometimes shows" or "can be a sign of" and
I would not even have thought of answering.
--
Ben.
Well if you're worried about scope you should refactor your code so
your functions do but a single [or few] task(s). Then if you have
some function-scoped counter variable like 'x' or 'i' or whatever it's
not a big deal. Note that doesn't mean I tend to use single letter
variables. For me something like 'x', 'y' or 'z' is for things where
I need a loop but the value of the counter is not used outside the
loop, e.g.
int array[5];
int x;
for (x = 0; x < 5; x++) {
array[x] = rand();
}
Now if I wanted to know the first odd one I'd have
int odd;
for (odd = 0; odd < 5 && !(array[odd] & 1); ++odd);
(where 'odd' would be declared up top).
Tom
> On Jan 8, 8:13 am, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
>> Them's fight'n words!
>>
>> When I write in a language that permits such things, I design my code
>> and think about my algorithms just as carefully but I then clean it up
>> (to my mind) by moving declarations so that all names have as small a
>> scope as possible and so that (where possible) they are initialised in
>> the declaration. I accept that not everyone agrees that this makes
>> things clearer but it is style I like to use and to read when I find
>> it in other people's code. It is not due to "making up variables mid
>> thought"!
>>
>> BTW, all you needed was a "sometimes shows" or "can be a sign of" and
>> I would not even have thought of answering.
>
> Well if you're worried about scope you should refactor your code so
> your functions do but a single [or few] task(s).
Only if I don't already do that, which I do. Because I try to have
very simple and short functions, I often *don't* have mixed
declarations and statements. When they occur, I don't see any
advantage in avoiding them (unless I need to write C90 of course).
> Then if you have
> some function-scoped counter variable like 'x' or 'i' or whatever it's
> not a big deal. Note that doesn't mean I tend to use single letter
> variables. For me something like 'x', 'y' or 'z' is for things where
> I need a loop but the value of the counter is not used outside the
> loop, e.g.
Indeed. C99 even has a notation for that!
> int array[5];
> int x;
>
> for (x = 0; x < 5; x++) {
> array[x] = rand();
> }
>
> Now if I wanted to know the first odd one I'd have
>
> int odd;
> for (odd = 0; odd < 5 && !(array[odd] & 1); ++odd);
>
> (where 'odd' would be declared up top).
Why? What is better about your version than:
int array[5];
for (int x = 0; x < 5; x++)
array[x] = rand();
int odd = 0;
while (odd < 5 && !(array[odd] & 1))
++odd;
which is what I'd write? I (obviously) think mine is more obvious but
not to the point where I'd push it on anyone.
--
Ben.
While I'm actually not really against that notation I just don't use
it.
> int odd = 0;
> while (odd < 5 && !(array[odd] & 1))
> ++odd;
This however irks me on three levels
1) late-declaration inside a code block
2) initialized and declared at same time (*)
3) no {} braces (**)
(*) irks me because people often miss initializing things when
initializers are all over the place. I like having a block of
statements that initialize variables before the block of statements
that make up the logic of the function. It adds up [to simplifying
the code] when you write a function that has 12 parameters and 15 auto
variables [like a PKCS #8 encryption routine...].
(**) irks me because people tend to add statements intending them to
be in the (do-)while loop and forget that there is no bracing.
I've seen both (*) and (**) come up as bugs more often than I'd like
to admit in code that I work on [not that I've written mind you] that
I avoid those styles at all costs.
Tom
If you initialize and declare at the same time, how can you more easily
miss initializing things ? I would imagine that people tend to miss stuff
like this when the declarations are all at the top, and the initializing is
done somewhere else. Putting them together would lead to *not* forgetting
it, I would think.
With late declarations, the declaration, initialization, and use are all
close together.
SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
Because it can make it harder to read and figure out which are
initialized. I suppose if your declaration block were really well
organized, lined up, and clean, but for me it's just easier to have
them as distinct blocks. It's not like I'm saying what I prefer is
the only way, but from my experience I have caught bugs in code
written that way (e.g. hard to spot things that are not initialized or
properly initialized).
Just like you don't *have* to use {} for your while loops. But I've
found it to cause problems when people don't. So even for one liners
I tend to.
Sometimes a little investment up front in terms of how you present
your code reaps rewards later when you have to maintain it.
> With late declarations, the declaration, initialization, and use are all
> close together.
You can't always organize code into nice logical blocks (sometimes
initializing something depends on processing another input first).
But I have yet to find a case where late declarations made sense. I'm
for scope-wise declarations ala
if (...) {
int somevar;
...
}
When you use a variable limited in scope because polluting the larger
scope can be its own problem. But to me when I see code like
for (...) {
...
}
int somevar = somefunc();
if (somevar) { ... }
It just smacks of "oh yeah, let's add this in the middle" and not well
thought out. Like if you knew in advance you had to compute "somevar"
you should have declared it before. I think what I'm saying is that
the style is symptomatic of other problems in the development flow.
It's not like I don't evolve my functions over time and add new
variables, but usually the way I write something complicated is
1. Figure out the goal of the function [output from input]
2. write english pseudo code comments for every logical step of the
algorithm
3. Start writing the auto variables and parameters, choosing logical
names/types to suit the job
4. one-by-one I write code for each pseudo-code comment block
This technique has yet to fail me and always results in code that has
a logical top-to-bottom feeling to it. Here are my variables, here
are my initializations, here is my code, etc. You don't read it
thinking "this part of code between step 3 and 4 was just kinda wedged
in here ad hoc."
Tom
> On Jan 8, 8:53 am, Ben Bacarisse <ben.use...@bsb.me.uk> wrote:
>> Why? What is better about your version than:
>>
>> int array[5];
>>
>> for (int x = 0; x < 5; x++)
>> array[x] = rand();
>
> While I'm actually not really against that notation I just don't use
> it.
>
>> int odd = 0;
>> while (odd < 5 && !(array[odd] & 1))
>> ++odd;
>
> This however irks me on three levels
>
> 1) late-declaration inside a code block
> 2) initialized and declared at same time (*)
> 3) no {} braces (**)
Forget 3 -- I have no desire to argue that point either way. 1 is
just a statement, not an argument. I could equally say "early
declaration in block irks me" (I wouldn't, but you see the point).
> (*) irks me because people often miss initializing things when
> initializers are all over the place. I like having a block of
> statements that initialize variables before the block of statements
> that make up the logic of the function. It adds up [to simplifying
> the code] when you write a function that has 12 parameters and 15 auto
> variables [like a PKCS #8 encryption routine...].
I must be missing something. If you have a rule (as I do) that every
declaration must have an initialiser (much easier to satisfy if you
permit late declarations) then I think it is easier to miss out an
initialiser using /your/ style. For 15 auto variables I need to check
about 30 lines and make sure that no typos have caused something to be
missed:
int max_length = -1;
int max_width = -1;
int mixed_length = 12;
Is easier to check than
int max_length;
int max_count;
int mixed_length;
max_length = -1;
min_width = -1;
mixed_length = 12;
(min_width turns out to be one of the function's parameters).
> (**) irks me because people tend to add statements intending them to
> be in the (do-)while loop and forget that there is no bracing.
>
> I've seen both (*) and (**) come up as bugs more often than I'd like
> to admit in code that I work on [not that I've written mind you] that
> I avoid those styles at all costs.
I've seen your style come up as bugs lots of times too. I have no
proper data about the relative frequency of bugs using either style so
I can't say more than "it happens". That is why I have to resort to
my personal taste. There probably is some data somewhere, but most
studies I've seem conflate too many issues to resolve any one of them.
--
Ben.
Yes, people should be allowed their own choices but that goes both ways.
For me the version where x (bad choice IMO, should be i, x is for a
floating point type) is declared external to the loop has the fault that
it is not clear at the point of declaration/definition what x is for.
There are two problems with the C90 restriction (which IIUC was for the
benefit of compilers, not programmers)
1) It makes the definition remote from the point of use, and that
sometimes means there is no logical value that it can be initialised to
(and I do not accept code which has uninitialised variables -- they are
a problem waiting to happen)
2) They can cause maintenance problems. The unused variable warning
common in compilers demonstrates that this is a problem that compiler
writers have found worth addressing. And that warning is itself enough
of a problem so that C++ introduced unnamed parameters in order to
provide an in code way of suppressing it.
Of course we can get round the restriction by introducing a new block
where we would otherwise just want to declare a variable. And the
problem is small or non-existent in small functions. However it is not
always possible to write only small functions.
My personal preference is to declare variables as late as possible,
preferably at or immediately before the point of first use.
It adds up [to simplifying
> the code] when you write a function that has 12 parameters and 15 auto
> variables [like a PKCS #8 encryption routine...].
Matter of opinion. I find writing code with variable declarations
immediately prior to first use simpler to write, read and maintain.
However I find a function with 12 parameters scary. If they are 12
independent parameters the code is far too complicated. If they are not
then the data should be packaged into a suitable struct or structs.
>
> (**) irks me because people tend to add statements intending them to
> be in the (do-)while loop and forget that there is no bracing.
Yes, which is why my personal layout standard requires that such cases
must be written on a single line.
>
> I've seen both (*) and (**) come up as bugs more often than I'd like
> to admit in code that I work on [not that I've written mind you] that
> I avoid those styles at all costs.
>
I have rarely seen the first one come up when the code has been written
by an experienced programmer. But the second case is a cause of frequent
problems, but not where the controlled simple statement is written on
the same line as the controlling expression.
void somefunction(void) {
int i;
<loads of code>
{float i;
<loads of code>
{char i;
<loads of code>
i=0;
Which i is being assigned to here, and what's it's type? With mixed
declarations, it means having the scan the entire body of code between the
top of the function, and the the assignment, in case there is a late
declaration.
--
Bartc
You don't have what most people would call C99 late or mixed
declarations here -- all declarations are at the top of their blocks.
The problem with this code is shadowing the outer declaration. That
is bad style and *can't* be done if you use C99 mixed declarations
instead of starting a new block all the time. I am not sure what your
example is arguing against but I don't think anyone is suggesting that
style.
--
Ben.
I was specifically talking about the combination of late declaration
and 'initialize and declare', and you were claiming an example of this
combination to be bad partly because you dislike initialize-and-declare.
But as it turns out, you dislike it precisely in forms where all the
declarations are together, so doesn't that mean it specifically doesn't
apply to said example ?
)> With late declarations, the declaration, initialization, and use are all
)> close together.
)
) <snip>
)
) When you use a variable limited in scope because polluting the larger
) scope can be its own problem. But to me when I see code like
)
) for (...) {
) ...
) }
)
) int somevar = somefunc();
)
) if (somevar) { ... }
)
) It just smacks of "oh yeah, let's add this in the middle" and not well
) thought out.
And what if it doesn't ? If each and every variable were declared at the
latest possible moment (i.e. when it is going to be used first), then does
all of that smack of 'oh yeah lets add this' ?
Basically, what you're saying is you dislike it because some of the cases
you've seen were poor examples, and it reminds you of those.
) Like if you knew in advance you had to compute "somevar"
) you should have declared it before.
I don't see why. It all seems to boil down to your gut feelings.
So what do you do if the variable is const?
--
Ian Collins
I considered declarations at the top of any block, instead of just a
function block, to be mixed declarations.
If C99 simply allows declarations to be anywhere in a block instead of at
the top of it, that just makes things worse: all lines of code must be
examined for a declaration, rather than concentrating on the beginning of
blocks.
> I am not sure what your
> example is arguing against but I don't think anyone is suggesting that
> style.
I thought only C99 could do this. It seems it's possible to use bad style in
C90 too.
--
Bartc
No one else does...
> If C99 simply allows declarations to be anywhere in a block instead of at
> the top of it, that just makes things worse: all lines of code must be
> examined for a declaration, rather than concentrating on the beginning of
> blocks.
That's why variables are initialised at the point of declaration.
--
Ian Collins
In that case I find your coding style unacceptable in the sense that if
you were employed by me I would insist that you do not do this.
>
> If C99 simply allows declarations to be anywhere in a block instead of at
> the top of it, that just makes things worse: all lines of code must be
> examined for a declaration, rather than concentrating on the beginning of
> blocks.
Why? There are perfectly good tools to locate declarations in source
code. The days are long gone when it was necessary to do these things
manually.
In that case, you're wrong. Please learn some C before making
statements about it.
Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1
>> If C99 simply allows declarations to be anywhere in a block instead of at
>> the top of it, that just makes things worse: all lines of code must be
>> examined for a declaration, rather than concentrating on the beginning of
>> blocks.
>
> Why? There are perfectly good tools to locate declarations in source code.
> The days are long gone when it was necessary to do these things manually.
Tools are fine, but the code should stand by itself too.
(And why doesn't the tool, presumably part of the editor, just relocate a
declaration where it belongs, ie. near the top of the block, or (for those
of us who are old-fashioned), near the top of the function.)
--
Bartc
> On Jan 6, 1:21 am, jacob navia <ja...@spamsink.net> wrote:
>> I am trying to design and implement a standard container library
>> for C.
>>
>> I report about it regularly in this newsgroup.
>
> Write the library for C90 and release it under LGPL and maybe I might
> care about it.
>
> If the library requires lcc-win32 extensions and is proprietary you
> can keep it.
>
> Tom
Good to see you confirming more and more my initial guess that you were
an anti MS nutjob.
--
"Avoid hyperbole at all costs, its the most destructive argument on
the planet" - Mark McIntyre in comp.lang.c
> jacob navia wrote:
>> Richard Heathfield a écrit :
>>> jacob navia wrote:
>>>> Tom St Denis a écrit :
But meanwhile in the real world most people simple target Windows on
intel and NEED performance.
> On Jan 7, 4:31 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>> Tom St Denis wrote:
>> > On Jan 7, 12:19 pm, Marco <prenom_no...@yahoo.com> wrote:
>> >> Totally agree - if not written in standard C (unfortunately that still
>> >> means C90 today) then most folks just won't want it
>>
>> > Nothing wrong with C90. Only thing I borrow from C99 is long long. I
>> > think that VLA and mid-block declarations are bad coding practice.
>>
>> While VLAs have their obvious problems, I don't see how you can object
>> to something that shortens and clarifies code (mixed declarations and code).
>
> Because it's too easy to bury declarations/initializations in code
> making it harder to sort out if variables are properly initialized
> [and to what]. I prefer code like
>
> {
> declarations;
>
> initializations;
>
> code;
> }
How nOObish!
>
> I'm ok with things like
>
> if (blah) {
> int x;
> x = some_struct->member;
> // blah...
> }
>
> But I think declaring variables wherever is messy and shows a lack of
> forethought/design [e.g. you're just making up variables mid thought
> as opposed to fully thinking through your algorithm first].
>
> Tom
Crikey, you sure come out with some crackers.
Local declaration is THE way to do it since no namepsaces are unduly
polluted.
If you dont agree then I suspect your code is like something from the
ark.
for(int i=0; i<LIMIT;i++){}
Perfect, clean, readable.
Where do you get off making such ridiculous statements as "making up
variables mid thought" - what total and utter nonsense.
You really need to get a decent tool set. The location and setting of a
var should be one key press away.
>> [and to what]. I prefer code like
>>
>> {
>> declarations;
>>
>> initializations;
>>
>> code;
>> }
>
> How nOObish!
>
>>
>> I'm ok with things like
>>
>> if (blah) {
>> int x;
>> x = some_struct->member;
>> // blah...
>> }
>>
>> But I think declaring variables wherever is messy and shows a lack of
>> forethought/design [e.g. you're just making up variables mid thought
>> as opposed to fully thinking through your algorithm first].
>
> Local declaration is THE way to do it since no namepsaces are unduly
> polluted.
Functions already have a local namespace.
How big are your functions that you need to have multiple namespaces inside
them!
(I believe C allows you at least 1e50 distinct identifiers within one
namespace, and that's without even making use of case sensitivity.)
>
> If you dont agree then I suspect your code is like something from the
> ark.
>
> for(int i=0; i<LIMIT;i++){}
>
> Perfect, clean, readable.
Presumably you can also do this:
for(int i=0; i<LIMIT1;i++)
for(int i=0; i<LIMIT2;i++)
for(int i=0; i<LIMIT3;i++) int a=i+i+i;
Very neat.
--
Bartc
> "Richard" <rgr...@gmail.com> wrote in message
> news:hi9vb7$sfk$3...@news.eternal-september.org...
>> Tom St Denis <t...@iahu.ca> writes:
>
>>> [and to what]. I prefer code like
>>>
>>> {
>>> declarations;
>>>
>>> initializations;
>>>
>>> code;
>>> }
>>
>> How nOObish!
>>
>>>
>>> I'm ok with things like
>>>
>>> if (blah) {
>>> int x;
>>> x = some_struct->member;
>>> // blah...
>>> }
>>>
>>> But I think declaring variables wherever is messy and shows a lack of
>>> forethought/design [e.g. you're just making up variables mid thought
>>> as opposed to fully thinking through your algorithm first].
>>
>> Local declaration is THE way to do it since no namepsaces are unduly
>> polluted.
>
> Functions already have a local namespace.
Yes. I know.
>
> How big are your functions that you need to have multiple namespaces inside
> them!
Huh? Immaterial. Keep the variable definition where its needed. It makes
ZERO sense to bunch them at the top.
>
> (I believe C allows you at least 1e50 distinct identifiers within one
> namespace, and that's without even making use of case sensitivity.)
>
>>
>> If you dont agree then I suspect your code is like something from the
>> ark.
>>
>> for(int i=0; i<LIMIT;i++){}
>>
>> Perfect, clean, readable.
>
> Presumably you can also do this:
>
> for(int i=0; i<LIMIT1;i++)
> for(int i=0; i<LIMIT2;i++)
> for(int i=0; i<LIMIT3;i++) int a=i+i+i;
>
> Very neat.
I'm not quite sure what you think that contrived example proves. Did you
seem me extrapolating the "bunched variables" idea to something like all
globals declared in a remote file? No. because thats silly and childish.
A basic paradigm of writing maintainable clean SW is to localise
variables to where they are needed. It also helps protect against
possible misuse of said variables.
Bunching them at the top is plain silly.
How can it NOT be clearer when reading code to see someting like
if(f){
int myCount=getNumber();
callFunc(myCount);
}
than
if(f)
callFunc(myCount);
and having to go off searching for myCount.
It's ridiculous to even try to argue against the benefits of localised
variable definitions.
Because then it would be a fascist tool which enforces a particular coding
style which many consider to be bad. Whereas a tool which aids in finding
declarations does no enforcing whatsoever. Most programmers value freedom
I'd call such a tool fascist only if it forced that behavior on me,
any more than "indent" is fascist for enforcing brace layout. A tool
that rearranges code like that might be quite useful. If nothing
else, the analysis it would have to perform would likely catch a
number of errors.
But yes, I certainly wouldn't use an editor that forcibly moved
declarations around. Apparently bartc would. (That's not a
criticism, just an observation.)
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Agreed.
> It is for people that want to
> use linked lists without bothering to reinvent the wheel again.
They already don't need to... however if yours turns out to be good
enough it could supersede others. You certainly seem to be putting in
the amount of effort needed to make it good enough.
>> I don't need the complexities introduced by some of your design
>> decisions, such as your decision to make it so generic (I know exactly
>> what I need, and it will never need to swap to being a tree or hash or
>> whatever).
>
> OK. Then go onusing your lists.
Well, it was written by someone else and just improved by me... others
though were written by me.
> I mean, what I want is that newcomers
> (and oldtimers) that do NOT feel like reimplementing a binary search
> tree, or a double linked list from scratch can use a standard package
> that is immediately usable, comes with source code, and can be adapted
> at will.
<snip>
Plenty of those around. Having similar interfaces for a whole range of
types of contain could be useful, less to learn, so you might have an
advantage there.
Actually, I've only written linked lists two or three times, and each
time in a different language (once in assembler for a DSP, highly
optimised for the specific application as I did not have a cycle or byte
to spare).
--
Flash Gordon
I'm aware of that. You've miss-understood my point below...
>> I don't need the complexities introduced by some of your design
>> decisions, such as your decision to make it so generic (I know exactly
>> what I need, and it will never need to swap to being a tree or hash or
>> whatever). I've got something far simpler which was debugged years ago
>> which has everything needed for what it is used for.
>
> I don't know whether Jacob will achieve this (within the bounds of
> standard C), but being generic is one of the reasons behind the C++ STL.
> The beauty of the STL design is most users never see the complexity
> behind this, they just use the containers "as is". I fear C's inherent
> transparency will make this hard for Jacob to achieve.
I'm not talking about the complexity of using it as a programmer, I'm
talking about the complexity of the code, e.g. calling functions through
pointers instead of directly... when I've needed linked lists I've also
needed them to be as efficient as possible (in all but one case), so did
not want the overhead of function pointers which Jacob is using.
--
Flash Gordon
> bartc wrote:
> ) (And why doesn't the tool, presumably part of the editor, just relocate a
> ) declaration where it belongs, ie. near the top of the block, or (for those
> ) of us who are old-fashioned), near the top of the function.)
Because it doesn't belong there. Are you a programmer or a complete moron?
>
> Because then it would be a fascist tool which enforces a particular coding
> style which many consider to be bad. Whereas a tool which aids in finding
> declarations does no enforcing whatsoever. Most programmers value freedom
>
> SaSW, Willem
Not a bad reposte.
bartc is deluded if he really thinks all variable declarations should be
at "the top". That style is nothing more than a relic of "must do" from years
ago. As for the ridiculous comments from St Denis about putting all your
variables first makes you think more about he algorithm, well, laughable
comes to mind. There really is not other way to describe it.
Ah, I see.
>>> I don't need the complexities introduced by some of your design
>>> decisions, such as your decision to make it so generic (I know
>>> exactly what I need, and it will never need to swap to being a tree
>>> or hash or whatever). I've got something far simpler which was
>>> debugged years ago which has everything needed for what it is used for.
>>
>> I don't know whether Jacob will achieve this (within the bounds of
>> standard C), but being generic is one of the reasons behind the C++
>> STL. The beauty of the STL design is most users never see the
>> complexity behind this, they just use the containers "as is". I fear
>> C's inherent transparency will make this hard for Jacob to achieve.
>
> I'm not talking about the complexity of using it as a programmer, I'm
> talking about the complexity of the code, e.g. calling functions through
> pointers instead of directly... when I've needed linked lists I've also
> needed them to be as efficient as possible (in all but one case), so did
> not want the overhead of function pointers which Jacob is using.
Fair point. Maybe that's one reason attempts to build a generic C
container library haven't been successful. I don't mean successful
technically, there are plenty out there that work well, but successful
in adoption.
To be wildly adopted, a container library must have the following
properties:
1 - Be easy to use.
2 - Flexible.
3 - No performance impact over hand rolled code.
The C++ STL used templates, so it doesn't suffer the performance impact
of function pointers so it ticks all three boxes. A good C
implementation will tick the first two but will struggle with the third.
I guess without language support for generics, any two properties are
possible at the cost of the third.
--
Ian Collins
variable first for me are very ok,
i meet 0 problem with them, and for debugging they are easy to follow
variable first for me are very ok,
> I'm not talking about the complexity of using it as a programmer, I'm
> talking about the complexity of the code, e.g. calling functions
> through pointers instead of directly... when I've needed linked lists
> I've also needed them to be as efficient as possible (in all but one
> case), so did not want the overhead of function pointers which Jacob
> is using.
I'd tend to agree. A lot of link lists are really very simple (free
lists of reclaimed objects for example) and wrapping them in piles of
other stuff undoes some of the benefits (speed compared with
free/malloc) that you are aiming for.
But since I last wrote on this I've come up with a really good example
of where some more complicated standard data types would help. I'm
doing some character conversion stuff and am about to write some wrapper
code to call the (POSIX) 'iconv' function - this reads from one char
buffer and writes to another.
The prototype is:
size_t iconv(iconv_t cd,
char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
and it has a whole set of return values to say whether it stopped
because of an error, because it succeeded completely or because it ran
out of space to write the result.
Think just how much easier it would be to use this function if the
output parameters were replaced with some sort of "real string"
implementation - any one of the millions! You'd just pass the input
string and check for an error return. If no error, the result is in the
output.
--
Online waterways route planner | http://canalplan.eu
Plan trips, see photos, check facilities | http://canalplan.org.uk
> bartc is deluded if he really thinks all variable declarations should be
> at "the top". That style is nothing more than a relic of "must do" from years
> ago. As for the ridiculous comments from St Denis about putting all your
> variables first makes you think more about he algorithm, well, laughable
> comes to mind. There really is not other way to describe it.
A really good example of where I use block-scope variables is in large
switches in mini-language stuff. Sure, you could use a function table,
but it's often easier to do this.
For many commands you don't need any extra variables, for some you need
an integer, for another a character pointer, for another a specialised
structure. Having a pile of these all defined and pre-initialised at
the top of what could be pages of code is far less clear than
introducing a pair of braces and a variable just in the 'case' you need
them.
But not as easy as seeing the declaration and initialisation NEXT to the
lines you are debugging.
No one said its impossible, just that its EASIER when the vars used and
declared when and where you need them.
Frankly to argue this is NOT easier stinks of ineptitude to me.
If you're using Linux, your distribution probably provides something
very much like CPAN. The relevant libraries will come neatly packaged
with documentation and descriptions you can search for keywords. They
will be called lib* and can be installted with a tool like apt-get or
rpm.
Many of the libraries will be portable, of course.
> Flash Gordon wrote:
> > I don't need the complexities introduced by some of your design
> > decisions, such as your decision to make it so generic (I know exactly
> > what I need, and it will never need to swap to being a tree or hash or
> > whatever). I've got something far simpler which was debugged years ago
> > which has everything needed for what it is used for.
>
> I don't know whether Jacob will achieve this (within the bounds of
> standard C), but being generic is one of the reasons behind the C++ STL.
> The beauty of the STL design is most users never see the complexity
> behind this, they just use the containers "as is".
IMO, that is the beauty of STL for C++ users, and the danger for C
users. I _want_ to know how complex a container I use is. I want no
surprises. That's why I use C, and not Java or C++.
Richard
> Tom St Denis wrote:
> > On Jan 7, 12:19 pm, Marco <prenom_no...@yahoo.com> wrote:
> >> Totally agree - if not written in standard C (unfortunately that still
> >> means C90 today) then most folks just won't want it
> >
> > Nothing wrong with C90. Only thing I borrow from C99 is long long. I
> > think that VLA and mid-block declarations are bad coding practice.
>
> While VLAs have their obvious problems, I don't see how you can object
> to something that shortens and clarifies code (mixed declarations and code).
I object because IME it doesn't clarify the code. Oh, it _could_ be used
to define an object just before the code to which it logically belongs,
but IME if nearly always _is_ used in the thought process "Oh, damn, I
need another total counter! Better declare it right here, where I first
thought of it".
That's also why I do _not_ object to the specific case of for-loop local
declarations: because in that case, it is impossible to put the
declaration in a random place somewhere hidden inside the rest of the
code. It's always, guaranteed, right where it belongs.
Richard
The complexity of the standard C++ containers is defined in the language
standard, so there wont be any surprises.
--
Ian Collins
A common use case (at least for me) is for intermediate values of
complex expressions. A trivial example being:
const int systemPower = busVoltage(someBus) * loadCurrent(someBus);
Such values are naturally const, so they can't really be declared before
they are initialised.
--
Ian Collins
> (I believe C allows you at least 1e50 distinct identifiers within one
> namespace, and that's without even making use of case sensitivity.)
>
Do you mean 'allow' as in an implementation must provide (and a
portable progam may use) or an implementation _may_ provide?
5.2.4.1 specifies some 'minimum maximums', amounts an implementation
must provide (although formally only in 'one program' which may well
not be any program you want) including the following with
C89value/C99value :
- 127/511 identifiers with block scope [per] block
- 31/127 parameters [per] function
- 511/4095 file-scope identifiers per t.u.
- 127/1023 members of a struct or union; members of an enumeration are
ordinary identifiers in the containing scope, and I don't see anything
about the number of tags per scope or t.u.
The only obvious maximum maximum (!) is the number of distinct
identifiers using the specified (C89) or basic (C99) character set
of length up to 31 (C89) or 63 (C99) less keywords (negligible).
The former of these is in the general area of 1e55, and may be what
you were thinking of, but a program containing that many identifiers
could not be recorded in the universe. Possibly something like the old
BASIC CHAIN$ applied to universes would help -- but not any of us,
since we wouldn't exist when (if ever) the answer (42?) is produced.
> Presumably you can also do this:
>
> for(int i=0; i<LIMIT1;i++)
> for(int i=0; i<LIMIT2;i++)
> for(int i=0; i<LIMIT3;i++) int a=i+i+i;
>
> Very neat.
Indeed you can, although it's mostly useless, even if you (try to)
make the body less trivial.