a CPAN for C

I

Ian Collins

Tom said:
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).
 
J

jacob navia

Tom St Denis a écrit :
Write the library for C90 and release it under LGPL and maybe I might
care about it.

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...
 
K

Keith Thompson

jacob navia said:
Tom St Denis a écrit :

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.

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]
 
J

jacob navia

Richard Heathfield a écrit :
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.

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!
 
N

Nick Keighley

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)
 
T

Tom St Denis

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].

Tom
 
T

Tom St Denis

Tom St Denis a crit :



I really do not care about C90.

How can you use 64 bit integers in C90?

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
 
B

Ben Bacarisse

Tom St Denis said:
On Jan 7, 4:31 pm, Ian Collins <[email protected]> wrote:
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.
 
T

Tom St Denis

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). 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
 
B

Ben Bacarisse

Tom St Denis said:
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.
 
T

Tom St Denis

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 (**)

(*) 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
 
W

Willem

Tom St Denis wrote:
) 2) initialized and declared at same time (*)
)
) (*) 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...].

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
 
T

Tom St Denis

Tom St Denis wrote:

) 2) initialized and declared at same time (*)
)
) (*) 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...].

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.

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
 
B

Ben Bacarisse

Tom St Denis said:
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.
 
B

bartc

Ian Collins said:
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).

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.
 
B

Ben Bacarisse

bartc said:
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.

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.
 
W

Willem

Tom St Denis wrote:
)> 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.
)
) 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, ...

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.


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
 
B

bartc

Ben Bacarisse said:
bartc said:
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 [to] scan the entire body of code between
the top of the function, and the the assignment, in case there is a
late declaration.

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 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.
 
I

Ian Collins

bartc said:
I considered declarations at the top of any block, instead of just a
function block, to be mixed declarations.

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.
 
P

Phil Carmody

Tom St Denis said:
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.

In that case, you're wrong. Please learn some C before making
statements about it.

Phil
 

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,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top