Reversing a linked list

J

James Kuyper

It's a coding style issue. I use them for internal functions.

"coding style" is not a term ordinarily used to describe deliberate
adoption of practices that, according to the C standard, have undefined
behavior.
And it's not just me. You know who else happens to do that? The small
army of Linux kernel programmers.

Guess what: the Linux kernal is part of a C implementation. The key
reason why you're not supposed to use these names is because they ARE
supposed to use them. They're NOT supposed to use the names that are
reserved for your use.
The point is, it's not some bizarre coding style choice I made. It's
used by an army of highly skilled programmers (kernel code is
PAINFUL.) These people know what they're doing, more so than you or I.

Both Keith and I are very experienced programmers with a comprehensive
and detailed knowledge of precisely what it is that the C standard
requires and allows. I would not recommend automatically assuming that
those people know more than we do, just because they know a lot more
than you do.
And they use it.

Yes - because they know enough to recognize which name space has been
reserved for their use - it is NOT the same name space that has been
reserved for your use. I recommend you acquire the same understanding
they have; because that same understanding will result in you using very
different naming conventions than they do.
 
H

henry eshbaugh

"coding style" is not a term ordinarily used to describe deliberate
adoption of practices that, according to the C standard, have undefined
behavior.

I used a term where you didn't expect to see it. Deal with it.
Guess what: the Linux kernal is part of a C implementation. The key
reason why you're not supposed to use these names is because they ARE
supposed to use them. They're NOT supposed to use the names that are
reserved for your use.

The Linux kernel is _not_ a C implementation. Glibc is a C
implementation.
Both Keith and I are very experienced programmers with a comprehensive
and detailed knowledge of precisely what it is that the C standard
requires and allows. I would not recommend automatically assuming that
those people know more than we do, just because they know a lot more
than you do.

That's wonderful. My choices work for me. I never asked you to adopt
it, I never asked you to critique it, and I never asked to be involved
in a flame war with either of you. My choices are my choices and your
choices are your choices. What I decide to do with underscores is my
business.
Yes - because they know enough to recognize which name space has been
reserved for their use - it is NOT the same name space that has been
reserved for your use. I recommend you acquire the same understanding
they have; because that same understanding will result in you using very
different naming conventions than they do.

You realize that the kernel namespace, the glibc namespace, and the
application namespace are three distinct things, right?
 
H

henry eshbaugh

You haven't answered this question.

Absolutely nothing. I arbitrarily decided to put leading underscores
in. Apparently, some people have a problem with it.
[snip]

C99 7.1.3p1:

    All identifiers that begin with an underscore and either an
    uppercase letter or another underscore are always reserved for any
    use.

    All identifiers that begin with an underscore are always reserved
    for use as identifiers with file scope in both the ordinary and tag
    name spaces.

    [more reserved identifiers omitted]

    No other identifiers are reserved. If the program declares or
    defines an identifier in a context in which it is reserved (other
    than as allowed by 7.1.4), or defines a reserved identifier as a
    macro name, the behavior is undefined.

The behavior of your program is undefined because you used the name
"__foo".  It would have been well defined if you hadn't done that.

And yet it works the same on my platform. It's a trivial thing; if it
doesn't work for you, you can change it with ease.
I've give you the facts; what you do with them is up to you.

I choose to ignore you and revel in the glory that is my platform.
It's my business.

Critique my code for what it is, not how pretty one identifier is
compared to another.
 
H

henry eshbaugh

You should not imitate code in the kernel without knowing specifically
and exactly why they use a particular convention. They may be calling
internal functions of the C runtime library (CRT) where your code MUST
not. This is what is meant by "the implementation". The kernel must be
closely tied to the CRT because the CRT is part and parcel to the way
the kernel supports user applications.



Copying coding conventions where you do not understand the rationale
has a name: Cargo Cult

I write some kernel code. Habits die hard.
Kernel code is kernel code and user code is user code. By using kernel
conventions in your USER name space programs you are creating a
potential name space collision.

The kernel namespace is separate from user namespace. You have to
specifically link your code against the kernel to cause a namespace
collision. It's like saying having two applications running, both
calling different versions of foo() will have a namespace collision.
It's just not going to happen.
Using leading underscores is not an indicator of a good programmer,
quite the contrary, it is an indication of a novice C programmer who
is emulating a style he does not understand because he copy-pasted or
has been browsing the CRT sources and has seen the style used and
doesn't understand that the convention is RESERVED to the CRT.

__foo() isn't a function in the CRT. Neither is __list_reverse(). It's
safe to use.
The C standard requires that you don't use leading underscores in your
names for a very specific reason. Just don't do it.

The C implementation I use for my code doesn't. So I consider myself
at liberty to.
 
H

henry eshbaugh

Screw it.

I really don't care what you guys think, and you guys don't care what
I think. I use underscores. Deal with it. If you want to criticize the
code I wrote, fine. It's vulnerable to stack overflow attacks and has
a lot of overhead. Argue about that.

But don't pull me into a days-long argument about trivial decisions I
make about naming identifiers. It belittles all of us. It's pointless.
What works for me, works for me. What works for you, works for you.
 
K

Kleuskes & Moos

Screw it.

I really don't care what you guys think, and you guys don't care what I
think. I use underscores. Deal with it. If you want to criticize the
code I wrote, fine. It's vulnerable to stack overflow attacks and has a
lot of overhead. Argue about that.

But don't pull me into a days-long argument about trivial decisions I
make about naming identifiers. It belittles all of us. It's pointless.
What works for me, works for me. What works for you, works for you.

They were trying to educate you on namespaces, which happens to be a quite
important subject. Double underscores are just one example of that. On large
projects more elaborate conventions are in use to avoid name-clashes.

An attitude like yours makes it very unlikely that your career as a software
engineer will be very successful. Standards are enforced for a reason, and
it's not just pissing off newbies.

-------------------------------------------------------------------------------
________________________________________
/ Yow! I'm imagining a surfer van filled \
\ with soy sauce! /
----------------------------------------
\
\
___
{~._.~}
( Y )
()~*~()
(_)-(_)
-------------------------------------------------------------------------------
 
J

James Kuyper

Screw it.

I really don't care what you guys think, and you guys don't care what
I think. I use underscores. Deal with it. If you want to criticize the
code I wrote, fine. It's vulnerable to stack overflow attacks and has
a lot of overhead. Argue about that.

But don't pull me into a days-long argument about trivial decisions I
make about naming identifiers. It belittles all of us. It's pointless.
What works for me, works for me. What works for you, works for you.

This leave me curious. Is this a habit of yours - looking for constructs
that have undefined behavior, checking to see whether they work in some
useful fashion on your particular compiler, and if so, deliberately
going out of your way to use them?

I once saw a teenaged boy on a field trip at Griffith Park, in Los
Angeles. He climbed on top of the railing that was intended to protect
him from falling down into a deep ravine. He was trying to find out
whether or not he could retain his balance. If he could, then it was
"obviously" a perfectly safe thing to do; if not -- well, he apparently
hadn't bothered thinking about that issue. He was "right" - he was able
to balance on top of the railing; then he got yelled at by his teacher.
He didn't understand why anyone thought he'd done anything wrong - he
got very resentful. Your attitude toward programming reminds me of him.

I hope there's nobody underneath you when you fall.
 
M

Malcolm McLean

But don't pull me into a days-long argument about trivial decisions I
make about naming identifiers. It belittles all of us. It's pointless.
What works for me, works for me. What works for you, works for you.
The trivial is important. That's the lesson of software engineering.

Bool breaks libraries. Something as seemingly trivial as how you
choose to represent boolean variables can make a library more trouble
to use than it is worth. Similarly my Fuzzy Logic Trees program
suffers because there is no standard way to generate a NaN. This isn't
part of the core fucntionality of the algorithm at all, it's just in a
stupid CSV file loader. But it means that ypu might have to dive into
the code and fix it to make it compile on ypur particular system, a
major, major disadvantage.
 
K

Keith Thompson

henry eshbaugh said:
Absolutely nothing. I arbitrarily decided to put leading underscores
in. Apparently, some people have a problem with it.

The language standard has a problem with it.

[...]
And yet it works the same on my platform. It's a trivial thing; if it
doesn't work for you, you can change it with ease.

I could write a program that works if the hostname of the machine
it's running on is "kvetch", and fails randomly if it isn't.
The program would work just fine on my system, and I could make
the same argument you're making.
I choose to ignore you and revel in the glory that is my platform.
It's my business.

Yes, it is.
Critique my code for what it is, not how pretty one identifier is
compared to another.

If you post code in public, it will be critiqued. If you don't want it
critiqued, don't post it.

I am not critiquing it for "how pretty one identifier is compared to
another". If you think I am, then you still don't understand what I'm
telling you.

We are critiquing your code for what it is: non-portable code whose
behavior is undefined, for reasons clearly stated in the C standard.

And in case it's not clear *we're trying to help you*. Pointing out
problems in your code is not a personal attack.

If you want to write non-portable code, you can do so. Often there
are very good reasons for doing so (but not in this case, as far as I
can tell). What I recommend is that you should be *aware* of why and
how your code is non-portable, so you can make an informed decision.
 
K

Keith Thompson

Malcolm McLean said:
The trivial is important. That's the lesson of software engineering.

Bool breaks libraries. Something as seemingly trivial as how you
choose to represent boolean variables can make a library more trouble
to use than it is worth.

That's why C99 defines a bool type.
Similarly my Fuzzy Logic Trees program
suffers because there is no standard way to generate a NaN.

C99's <math.h> defines a macro NAN.

Neither of these solves the problem of supporting pre-C99
implementations, but you can at least use #if to test for
__STDC_VERSION__ >= 199001L (and perhaps eventually phase out the
rest of your maze of #if and #ifdef directives).
 
G

Gene

This group has lost many people. One of the reasons is that the
newcomers just ask a question or two, and do not see discussions
that try to explain code, teaching newcomers to the language how
a program works.

This is a second example (after hexdump.c) of commented code,
i.e. explaining step by step how a relatively simple operation
is done.

Reversing a linked list
-----------------------

  13     if (l->count < 2)
  14         return 1;
  15     Next = l->First;
  16     l->Last = l->First;
  17     Previous = NULL;
  18     while (Next) {
  19         Current = Next;
  20         Next = Next->Next;
  21         Current->Next = Previous;
  22         Previous = Current;
  23     }
  24     l->First = Previous;
  25     l->Last->Next = NULL;
  26     l->timestamp++;
  27     return 1;
  28 }

Since this is a tutorial, consider imparting something of value:
pseudocoding and rewrite.

/*
Algorithm:

Given List L
Set list R empty
while L is not empty
top = pop(L)
push(R, top)
end
return R
*/
int Reverse(List *lst)
{

// Error checking and update counting omitted...

ListElement *L = lst->First, *R = NULL;
while (L) {
// pop()
ListElement *top = L;
L = L->Next;
// push()
top->Next = R;
R = top;
}
lst->Last = lst->First;
lst->First = R;
return 1;
}
 
D

David Resnick

The C implementation I use for my code doesn't. So I consider myself
at liberty to.

If you don't value portability, or even guaranteeing that your code
will compile/link with the next upgrade of your implementation, that
is of course a choice you get to make. But of the portability/
maintainability compromises to choose (and most or all of us make such
choices all the time), stepping on the well defined language namespace
seems to me an odd one. Folks are welcome to define macros that start
E followed by an uppercase letter, or variables that start __blah or
_Quux, but given easy alternatives not obvious to me why that is a
good choice in general.
 
P

Phil Carmody

henry eshbaugh said:
I write some kernel code. Habits die hard.

linux-2.6$ git log | grep -i eshbaugh
linux-2.6$
The kernel namespace is separate from user namespace. You have to
specifically link your code against the kernel to cause a namespace
collision. It's like saying having two applications running, both
calling different versions of foo() will have a namespace collision.
It's just not going to happen.

You have misunderstood Geoff, your retort is irrelevant to his point.
The name space collision Geoff is talking about is between your user
code and the CRT.
__foo() isn't a function in the CRT. Neither is __list_reverse(). It's
safe to use.

Do you know how difficult it would be for me to change the CRT I use
at home and at work such that it did have a __foo()? Don't think too
long, as I'd already have done it.
The C implementation I use for my code doesn't. So I consider myself
at liberty to.

If you only care about your code running on one platform and only
using one toolchain - at that, only one version of the platform and
the toolchain - then you have the right to construct your own play
area where you break the rules. However, do not expect others to join
you there, and certainly do not expect others to want you to join
their play area.

Phil
 
S

Seebs

Screw it.
'k.

I really don't care what you guys think, and you guys don't care what
I think. I use underscores. Deal with it.

I think I'll deal with it by plonking you.
But don't pull me into a days-long argument about trivial decisions I
make about naming identifiers. It belittles all of us. It's pointless.
What works for me, works for me. What works for you, works for you.

They are only trivial if no one else ever has to deal with your code.

Happily, I expect that anyone with your attitude towards possible improvements
will ensure that.

-s
 
S

Seebs

It's a coding style issue. I use them for internal functions.

It's a style issue such that if I see something like that in code I assume
that code is where the bug is. And usually I'm right.
And it's not just me. You know who else happens to do that? The small
army of Linux kernel programmers.

I think it may not be too extreme a speculation to suggest that the Linux
kernel is not expecting to be run as a userspace application against someone
else's C library.
The point is, it's not some bizarre coding style choice I made.

Yes, it is.
It's used by an army of highly skilled programmers (kernel code is
PAINFUL.) These people know what they're doing, more so than you or I.
And they use it.

I would not particularly be inclined to bet that any given Linux kernel
programmer knows more about writing C than Keith does.

I would also not consider the Linux kernel to be a good sample of general
coding style. The kernel is not concerned with the behavior of its
host library. :)

-s
 
P

Phil Carmody

henry eshbaugh said:
I used a term where you didn't expect to see it. Deal with it.


The Linux kernel is _not_ a C implementation. Glibc is a C
implementation.

You think the linux kernel links to glibc? So you believe that
kernel code could just include a call to, say strtok(), and
that would get resolved to glibc's implementation?

Knock, knock, knock - who's that at the door? Oh, it's Captain
Whatthefuck.

I'll have some of what you're smoking. But I'll only partake
once I've finished my day's work as a linux kernel programmer
and one of the company's tree maintainers, thank you. (Yay, 8
days until I am _the_ maintainer, thanks to the Elopocalypse.)

Phil
 
P

Phil Carmody

Keith Thompson said:
That's why C99 defines a bool type.


C99's <math.h> defines a macro NAN.

There's also double nan(const char *) too, but "only if the
implementation supports quiet NaNs".

However, the only reason I can think of that you would need a NaN is
in sanity checking to make sure you initialised something in a remote
calculation. First blank things with NaN, and shit hits fan if you use
if before it's initialised. But that's at the assert() level of code,
you don't need it in release-quality production code.

By the time you're actually trying to juggle NaNs, you're in
intrinsically platform specific code, as not all platforms support
them, and those that do support them in different ways, I wouldn't
expect there to be a portable way of dealing with them.

Phil
 
M

Malcolm McLean

 But of the portability/
maintainability compromises to choose (and most or all of us make such
choices all the time), stepping on the well defined language namespace
seems to me an odd one.
The reserved namespace is badly chosen.

For instance the idenitifiers stripspaces() and island step over it,
as does the macro ENDIANNESS.
 
D

David Resnick

The reserved namespace is badly chosen.

For instance the idenitifiers stripspaces() and island step over it,
as does the macro ENDIANNESS.

Therefore? We should ignore the implementation namespace? I miss
your point, or is it just a comment? When you find a "perfect"
language, please let me know. In the meantime, as language warts go,
could be worse. Yes, having language level support for namespaces
would fix it, but, well, that isn't "C", at least not as of now.

-David
 
M

Malcolm McLean

Therefore?  We should ignore the implementation namespace?  
If I need an identifier like "strength" or ENGLAND. which is in the
reserved namespace but very unlikely for an implementation to actually
use, I just use it, rather than having SCOTLAND, WALES, IRELAND and
EnGLAND, or whatever subterfuge is necessary.
 

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

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top