arithmetic on a void * pointer

E

Eric Sosman

Helpful C swamis,

In the good old days, any self-respecting C compiler knew what you meant
when you did arithmetic on a void * pointer, i.e. that the units were
bytes.

If by "the good old days" you mean "before the ANSI Standard
in 1989," you might be sort of right. In those days there was no
formal definition of C, and all manner of compilers bestowed the
"C" label on themselves. Some of those may have had a void* type
(K&R C did not), and some of those may have permitted arithmetic
on that type. I never ran across a pre-ANSI compiler with these
characteristics, but there were lots and lots of compilers I
never ran across at all.

Also, if it's pre-ANSI C you speak of, I dispute the adjective
"good."

Starting with ANSI C, which first (formally) introduced void*
to the language, no conforming compiler has ever permitted
arithmetic on void* values. The only compiler I happen to know
of that permits it is gcc (in a non-conforming mode), but perhaps
there are others. There are certainly "self-respecting" compilers
that follow the language definition and forbid it.
Then someone decided that we would all be more productive somehow
if the compilers couldn't figure out obvious things like that on their
own. So now you can't do arithmetic on void * pointers.

It'd be bogus. Since void is an incomplete type, the sizeof
the thing a void* points at is unknown. That's what makes void*
useful in the first place: You can point it at anything at all
without worrying about the sizeof the target. The very same void*
variable can point at a char, an int, and a struct foobar, all
during a single execution of one program. What is "the" size of
all these different targets?

Here's another incomplete type, and an example of how it
might be used in a hypothetical implementation of an ADT:

struct unknown; // incomplete type
struct unknown * newUnknown(int); // a "constructor"
struct unknown * uptr = newUnknown(42); // instantiation

Okay, uptr (we'll suppose) now points at a struct unknown instance.
If you now do ++uptr, what ought to happen? Should the address
advance by one byte? Forty-two bytes? Eleven? Where is the
"one past the end" location for the struct unknown object whose
size is a mystery? Arithmetic on a void* encounters exactly the
same problem: The size of the target is unknown, so the compiler
can't know how far to advance the pointer.
Ok, fine. So I adjusted, I would do this:

void *buf;
int n;

(char *)buf += n;

This is also bogus, for the same reason (double)n += 0.42
would be bogus. The left-hand side is an expression with an
operand, an operator, and a value, not an object to which you
can assign something (I'm speaking somewhat loosely here; look
up the term "assignable lvalue" for a more rigorous treatment).
But now I'm getting nastygrams like "warning: target of assignment not
really an lvalue; this will be a hard error in the future". Once again
someone, probably the same person, decided that compilers shouldn't have
to burden this great responsibility of understanding obvious things like
that. (And why a cast of a pointer to another pointer type is no longer
a pointer, I have no idea.)

Because the cast is an operator that derives a value from
its operand. Try this one: (char*)(ptr + 42) = "Hello". Where
do you think the pointer to 'H' should be stored, and why?
So now what am I supposed to do? It starts to get just downright silly.
E.g.

void *buf;
int n;
char *cmon;

cmon = (char *)buf;
cmon += n;
buf = (void *)cmon;

Is there a better way to work around this, at least until the *next*
dumbing down of the language?

buf = (char*)buf + n;

And before you say "That's just dim-witted," ponder

buf = (int*)buf + n;

It seems to me there are two misconceptions buried in your
mental model of the language. One is the notion that a pointer
is "just an address," which is wrong: A pointer is an address
*and* a type, and the type is important. The second mistake is
to think of the cast operator as meaning "let's pretend this
thing is of a different type," when in fact it means "take the
value of this thing, convert it to a new type, and deliver the
converted value (which may even be unequal to the original)."

You are not the first to fall victim to these two mistaken
notions, nor will you be the last.
 
S

spinoza1111

Human sacrifice, dogs and cats living together, mass hysteria!

Mark

Mark, are you the guy in the wikipedia article? Whether you are or are
not, you appear to be one of the few intelligent people to wander in
here. Be advised of the bozo factor, including the incorrect
designation of bozoidness being hurled by bozos.
 
S

spinoza1111

Sez you.  If what you said was correct, then we should never be able
to cast a pointer to another pointer type, since that object it's
pointing to doesn't exist.

Huh?

If you're going to snip context, can you please indicate that you're
doing so?  Here's what I wrote:

    An lvalue designates an object.  For the result of a cast to
    designate an object, there has to be some object *of the specified
    type* for it to designate.  Since the operand of the cast was of a
    different type, there is no such object.

I'm not talking about the object (if any) to which the pointer points.
I'm talking about the pointer object itself.

For example, given:

    void *vp = ...;
    ... (char*)vp ...

vp is an object of type void*.  There is no object of type char*.
There is a *value* (not an lvalue) of type char*, the result of
converting the value of vp from void* to char*.

[...]
No I would not want that.  l is not a pointer.

And why does that matter?
Uh oh.  Now I'm really worried, if having different, non-transferrable
data pointer representations is permitted by the C standard.  I sure
hope you're wrong.

I'm not.  Different pointer types can have different representations.

Consider a system where a machine address points to, say, a
64-bit word, but the C implementation specifies an 8-bit byte.
Word pointers can be represented as machine addresses, but byte
pionters need an additional offset stored somewhere.  (I've worked
on such a system.)

You might take a look at section 4 of the comp.lang.c FAQ,
I certainly would expect the code above to work, though I can think of
no reason to do that since NULL is of the type void *, and so can be
assigned to other pointers without an explicit cast.  It should just
be ptr = NULL.  (At least that's what the compilers allow -- I hope
that doesn't get messed up too.  I don't want to have to cast NULL
every time I use it.)

I just used NULL as a trivial example.  The point isn't whether it's a
sensible thing to do, it's whether it's legal.

ROTFLMAO, another for the Red Book, along with Heathfield
("comp.programming not about programmers", "Nilges not in comp.risks",
"functions return expressions") and Seebach ("the 'heap' is a DOS
term"):

"The point isn't whether it's a sensible thing to do, it's whether
it's legal"

....meaning it must conform to the Holy Standard. When asked why, the
*imams* of the Standard tell their *taliban* that their code must be
portable.

This is completely absurd. C is so dangerously NON portable that ANY
port needs a line by line analysis for gotchas no matter how "good" is
the code. When people want to be portable they use Java.

The reality is that if it works on a specific compiler, that is the
goal in 99.9% of cases.
 
S

spinoza1111

You don't seem to have understood the difference between the pointer
and the thing pointed to.

I have said it before, and I'll say it again. You and the other regs
consistently morph friendly technical discussions into cybernetic
lynchings by starting this shit, Peter. You start using language that
instead of sticking to the technical issues, challenges the
professional standing of your interlocutor. You did this with Schildt,
and now it appears that you are doing it to Adler. And he's the guy
with the track record in technology, it appears now from his email and
the wikipedia article.

He wants to use C in one of the ways it was originally intended: as a
(somewhat) machine independent assembly language. Had you ever
programmed in assembler language, you'd know that it uses puns in many
cases including "void" pointers: in fact, in pure assembler, all
pointers are void, and we somehow figured out how to manage this. It
wasn't great (which is why I debugged a nonworking Fortran compiler in
1972) but it was doable.

Whereas C programmers in a contradictory fashion want people to think
of their language as simultaneously Adult (portable and Standard) yet
also Close to the Machine where they can, like Peter Pan, have Fun.
 
S

spinoza1111

For example ...?

At runtime, I would have the choice:

(1) Let the pointer to int be a four byte (assuming the existence of
bytes in the first place) value which has to be multiplied by four
every time I use it (assuming byte addresibility and 32 bit ints)

(2) Let the pointer be a byte address at all times which is always
divisible by four if all ints must be aligned.

Number (1) is a major performance boner: you might as well be using
array indexes in Visual Basic.

I understand that pointers come in different flavors, especially on
different machines. But in most cases, having different pointer
"shapes" in machine language is a design flaw.
 
K

Kenny McCormack

I wasn't talking about the standard. I was talking about the compilers.


You're correct. I meant dumbing down of the compilers to agree with
the religious extremism of the standard.


Thank you. That's what I'll do. Of course, at the loss of the
expessiveness and readability of the wonderful += operator of C.

Mark - I'm curious. How did this issue become a problem for you.

Presumably, you were tootling along just fine, doing arithmetic on your
void *s, thinking nothing of it. Then, something changed to make it a
problem. Did you switch compilers (I'm going to guess from gcc [a
sensible compiler] to something else, something more religious, something
more in keeping with the tards on this newsgroup)

Or, did you "upgrade" to a newer version of gcc, that has more warnings?
Are you under some corporate mandate that your code must compile w/o
warnings?
 
K

Kenny McCormack

Oh, I see -- another post here.

I wasn't convinced by the argument that because sometimes casting
results in something that's not an l-value, that you must then assume
that all casts cannot be an l-value.

Mark

Then you're just not into the dogma in force around here.
 
S

spinoza1111

Nonsense, the size is the size of the data pointed to.  What the data is
is irrelevant.


How so?  the length is a length in bytes.  I really think you either
don't understand the concept of void*, or you are being obtuse.


Eh?

consider

int n;
write( &n, sizeof(n) );


Nowhere does void implicitly have a size.


So nonsense like:

int n;
int *p = n;

...

void* v = p;
++v;

would become legal?

It is well known that legal C code can be bulls*t. There is (was?)
even a contest for producing the worst (most obfuscated) but legal
(compiles and runs) C code. C is a used Ford Pinto, fun to drive in
its own way as long as you realize you're putting your life on the
line.
 
K

Kenny McCormack

Morris Keesan said:
I've been programming in C since before the "void" type was invented, and I
don't think I've ever encountered a compiler that would do arithmetic on
(void *) objects. Since arithmetic on pointers is defined in terms of the
size of the object pointed to, why would you assume that sizeof(void) == 1?

You've never used gcc?

Not that that is impossible, of course, but, as the saying goes, it
sounds like bullshit to me.
 
M

Mark

spinoza1111 said:
No, from the standpoint of science (linguistics), no standard can
"define" C. This is because independent of the standard are all sorts
of C compilers with a fuzzy relation to any one formal definition of
C. Somewhat like world received English, C is what intelligent users
"say" it is. In addition, linguists also add that the language should
be the canonical user's first language, but this is impossible with C,
of course.

Using norms from the realm of natural languages isn't necessarily
helpful. Natural languages and computer languages share much in common,
but much is not common. Indeed, you note one further down, when you
point out that it would difficult for anyone to claim C as their first
language.

Whilst it's true that (in line with natural languages) there are many
dialects of C, programming languages are (I would argue) necessarily
constrained by the need for programmers to agree very specific outcomes
to very specific constructs; where (most) humans will happy handle (a
certain level of) variation in usage and still be able to comprehend the
essential meaning of the words, most computer languages and their
execution environments struggle to be more than literal. As a result
(and in my experience), languages which don't have formal definitions
which implementations *try* to conform to tend to either exist in a
monoculture (as single implementations) or fail to gain widespread
adoption.

What I'm saying is, there *is* a widely agreed definition of what C
"is", and that's not invalidated by the fact that most implementations
(to one extent or another) fail to fully conform.

To address the issue of "C is what intelligent users say it is", to an
extent I agree. Equally (as with revisions of the OED), it's also
almost the other way round in that "C adapts to reflect what intelligent
users demand". As a result, subsequent revisions of the standard tend
to take on board the best ideas of non-conforming implementations and,
as a result, many features from many different "C" compilers have ended
up as part of future standards. That's as it should be.

It would be nice to think, however, that both compiler writers *and*
software engineers (try to) only go outside the standard deliberately,
and are fully aware of what that means. As someone who has (over the
course of a twenty year career) had to deal with cross platform
development, environment changes, moves between 16, 32 and 64 bit
implementations and so on, life is *much* easier where that is built
into the assumptions of the developers from the start.

Of course, it also depends on the context. If the code is *known* to be
used within quite limited environments and, perhaps more significantly,
if it's known to be short-lived*, this becomes less important.

* I have, however, known code that "will only be in use for the next
couple of months" that suddenly became permanent.
But if it is a pointer in truth, why would dereferencing it cause
problems, oh Divine Master? Yea this is hard for us mere mortals to
understand! For what is a pointer but that which dereferenceth?

In C, a pointer is something which can contain something which looks
like a pointer. If it contains a valid pointer, it can be safely
dereferenced. If it contains something which looks like a valid pointer
but isn't (isn't a pointer or isn't valid), it will cause a problem.
Oh divine Master, thou speakest horseshit indeed: for hath not C a
register declaration? And are we not supposed to think ahead a little
bit to what happeneth when our code runneth? Yea, verily they speak
with forked tongue who say, "behold: C is close to the Machine, and if
thou codest in C, thou shalt be one with the Machine, warm in winter
owing to the heat of its circuitry, cool in summer's heat owing to its
air conditioning", but then slay those, as Seebach has slain those,
who darest to speak of the mysteries of runtime such as the Stack, or
here the Register.

Unfortunately, "register" is somewhat tricky concept in C. There is no
obligation for the register keyword to do anything. The "register"
storage-class specifier hints to the compiler that this storage
declaration declares an object (small-o) which the compiler should try
to ensure fast accesses to. That request may be validly disregarded.
In some implementations (and originally, hence the wording) this may
be achieved by ensuring that it's kept in a register. If an
architecture has a way of producing fast accesses which doesn't involve
registers, the compiler is perfectly entitled to emit code as a direct
result of "register" which has nothing to do with registers.
 
S

spinoza1111

And therein lies the nub of his problem (I think). A void* is a generic
pointer to an object of unspecified type and so unknown size. The rules

A void pointer is a thing of holy dread
It may only be copied, writ or read
If thou dost arithmetic on a void pointer
Thou shalt be damn'd in the hereinafter.
Hark, I here Satan and his imps
Coming to get you twerps and gimps
Who darest to increment a void pointer
Jes' cuz it's permitted by your compiler!
Hell and Perdition yawn for thee
Heaven's trumpets summon me
For I codeth standard C
And I shall wear dem golden sandals
Whilst in Hell thou'rt sodomiz'd wif candles!
 
K

Kenny McCormack

Mark Adler <[email protected]> responded to our own little Kiki
thusly:
....
Uh oh. Now I'm really worried, if having different, non-transferrable
data pointer representations is permitted by the C standard. I sure
hope you're wrong.

Here, I think you are barking up the wrong tree. Kiki is wrong about
just about everything and anything that is useful or relevant, but when
it comes to the C standard, he is never wrong. As we know, he sleeps
with a copy of it under his pillow.

You might want to search Google groups for a post I made some time ago
about Kiki preparing for a vacation on a sunny tropical isle. I think
if you search for author (Kenny MacCormack - or however I spell it) and
the word "lotion" (or maybe "oil"), you should find it.
 
S

spinoza1111

Well, as far as I can tell, it really means "ALL the warnings the gcc
development team think might be handy" - i.e. hardly any. When writing
portable C, at a bare minimum you want -W -Wall -ansi -pedantic

Portable C is an oxymoron. Any responsible port of C takes if done
properly the same time as a rewrite in Java, or more. Therefore, any
organization with an inventory of C contemplating a port to a new
machine should rewrite the code in Java UNLESS the code is truly time-
critical, because the time it takes to do an acceptable job of
verifification that the C code will work on the new platform can be
used to rewrite in Java, which is portable, period.
 
S

spinoza1111

     If by "the good old days" you mean "before the ANSI Standard
in 1989," you might be sort of right.  In those days there was no
formal definition of C, and all manner of compilers bestowed the
"C" label on themselves.  Some of those may have had a void* type
(K&R C did not), and some of those may have permitted arithmetic
on that type.  I never ran across a pre-ANSI compiler with these
characteristics, but there were lots and lots of compilers I
never ran across at all.

     Also, if it's pre-ANSI C you speak of, I dispute the adjective
"good."

     Starting with ANSI C, which first (formally) introduced void*
to the language, no conforming compiler has ever permitted
arithmetic on void* values.  The only compiler I happen to know
of that permits it is gcc (in a non-conforming mode), but perhaps
there are others.  There are certainly "self-respecting" compilers
that follow the language definition and forbid it.


     It'd be bogus.  Since void is an incomplete type, the sizeof
the thing a void* points at is unknown.  

This is incorrect. Since C is a weakly typed and punning language
which permits values to be casted with few constraints, what you call
an "incomplete" pointer is a Von Neumann pointer to the smallest
addressable unit, whose size is by definition, 1. C assumes von
Neumann architecture.
That's what makes void*
useful in the first place: You can point it at anything at all
without worrying about the sizeof the target.  

On the one hand, the *imams* here of Holy C claim of its pathology
(such as the fact that sprintf() can be broken at any time in running
code simply by passing it a to-long string) that if one is "competent"
one won't get bitten (although it is impossible to write code that
prevents the sprintf() problem without predeciding a limit that should
not be predecided).

On the other hand, having blessed all sorts of nonsense, they suddenly
get religion when it comes to void pointer arithmetic, like the vicar
returning from the whorehouse goin' back to church!

The very same void*
variable can point at a char, an int, and a struct foobar, all
during a single execution of one program.  What is "the" size of
all these different targets?

     Here's another incomplete type, and an example of how it
might be used in a hypothetical implementation of an ADT:

        struct unknown;                         // incomplete type
        struct unknown * newUnknown(int);       // a "constructor"
        struct unknown * uptr = newUnknown(42); // instantiation

Okay, uptr (we'll suppose) now points at a struct unknown instance.
If you now do ++uptr, what ought to happen?  Should the address
advance by one byte?  Forty-two bytes?  Eleven?  Where is the
"one past the end" location for the struct unknown object whose
size is a mystery?  Arithmetic on a void* encounters exactly the
same problem: The size of the target is unknown, so the compiler
can't know how far to advance the pointer.
Apples and oranges. A struct has different lengths. Memory has a
smallest addressable unit. The fact that there might be constraints on
addresses at the smallest unit (alignment) doesn't change this.
     This is also bogus, for the same reason (double)n += 0.42
would be bogus.  The left-hand side is an expression with an
operand, an operator, and a value, not an object to which you
can assign something (I'm speaking somewhat loosely here; look
up the term "assignable lvalue" for a more rigorous treatment).

Brilliant. Yet Another piece of silliness alongside sequence points,
invented PURELY to pretend that C is a grown-up's language: the
Unassignable LValue! A pointer that cannot be dereferenced! It's a
bird! It's a plane! It's a mule!
 
S

spinoza1111

Then you're just not into the dogma in force around here.

Yea verily hath he not the dogma
This bird dog hath not gotten the word, dawg:
He hath not taken Communion
Eaten the dog's dinner made here of C:
He hath not fed of the canine repast
He hath drunk not the kool ade
He hath not eaten of the insane root
Which makes men mad, having drunk the C
As sailors do when no land they see,
And thirst for drink other than pee.
If he loiters, and if he stay
Then every night and every day
He will be dogged by the hell hounds
And plagued shall he be with the noisome sounds
Of the Parliament of foulish fools
Feeding on fantasies like churlish curs.
But Adler, mighty Eagle become a man
Has already I wot said, doggone it
This place is Bedlam, a place of burning
And the dancing of trolls inflamed.
It is not fit place for a puissant Eagle:
It is a place for Pup, mutt, stray and Beagle.
 
R

Richard Tobin

Mark Adler said:
In the good old days, any self-respecting C compiler knew what you
meant when you did arithmetic on a void * pointer, i.e. that the units
were bytes.

I'll ignore most of your post because it's already been addressed.

Initially character pointers served three purposes: pointers to real
characters, pointers to generic bytes, and pointers to "opaque"
objects - objects of locally unknown type. With the addition of void
pointers, we now have two types for three kinds of thing.

When void pointers are used for objects of unknown type, it's
a good thing that you can't do arithmetic on them. It allows
the compiler to detect some errors that might otherwise go
undetected. On the other hand, this means that you need to use
character pointers to do byte arithmetic.

Incidentally, even if we had three types for the three kinds it
wouldn't always be clear which to use. Consider qsort(). The items
are opaque in that their addresses are going to be passed to a
comparison function which does konw their type and will probably cast
them appropriately, but they are generic bytes in that qsort() will
move them around simply by knowing their size.

-- Richard
 
K

Kenny McCormack

spinoza1111 said:
I have said it before, and I'll say it again. You and the other regs
consistently morph friendly technical discussions into cybernetic
lynchings by starting this shit, Peter. You start using language that
instead of sticking to the technical issues, challenges the
professional standing of your interlocutor. You did this with Schildt,
and now it appears that you are doing it to Adler.

Yup. Well put.

You can always see that, in pretty much any Usenet thread, but most
especially in CLC - where they do an especially good job of hiding it -
of pretending to be objective - which just makes it worse. That point
at which the thing turns personal - in TA terms, starts sending "You
messages". You don't understand this. You probably wet your bed as a
child. Etc, etc.

But I have to say that, I understand where these people are coming from,
and, believe me, it isn't a pretty place. I have long since stopped
getting angry at it. I just feel pity for them.
 
K

Kenny McCormack

Apparently -Wall really only means -Wsome.

Yes. This has been a source of error/confusion with GCC for quite some
time. I think they are going to change -Wall to something like
-Wcommon.

FWIW, I always compile with -W -Wall, which gets everything important.
I never compile with -crippled (aka, -pedantic).
 
S

spinoza1111

Using norms from the realm of natural languages isn't necessarily
helpful.  Natural languages and computer languages share much in common,
but much is not common.  Indeed, you note one further down, when you
point out that it would difficult for anyone to claim C as their first
language.

OK, there are differences. However, the alternative (C as math or a
formal language) fails to fit the facts.
Whilst it's true that (in line with natural languages) there are many
dialects of C, programming languages are (I would argue) necessarily
constrained by the need for programmers to agree very specific outcomes
to very specific constructs; where (most) humans will happy handle (a
certain level of) variation in usage and still be able to comprehend the
essential meaning of the words, most computer languages and their
execution environments struggle to be more than literal.  As a result
(and in my experience), languages which don't have formal definitions
which implementations *try* to conform to tend to either exist in a
monoculture (as single implementations) or fail to gain widespread
adoption.

The problem is that C's "standardised formality" is bought by
simultaneously calling things undefined and permitting vendors to
continue to support the "undefined" concepts. C is simply not
formalized save in the most "Platonist" sense as opposed to the
"Intuitionist" sense, where Platonism in the philosophy of mathematics
is the belief that mathematical objects exist *in reality* whether or
not we know them, whereas Intuitionism is the belief that it doesn't
exist until it's constructed.

Now, it would seem that Intuitionism would be the philosophy of the
competent programmer.

[And at this point let me mention my sadness on hearing that Dik
Winter has passed away, for this type of statement is what he loved to
jump on: perhaps as a Dutch person he felt a special connection with
Intuitionism, and he always had something interesting to contribute to
the discussion, especially when I mentioned Brouwer or Dijkstra.]

Applying this to programming, to say "doing arithmetic on a void
pointer has no result" is Platonic since Adler showed (constructively
and in an intuitive/Intuitionist way) how this has a sensible meaning:
the sizeof a void pointer is the sizeof the smallest unit of memory.
It is Platonist to insist on the (unconstructed) possibility of an
alternative interpretation.
What I'm saying is, there *is* a widely agreed definition of what C
"is", and that's not invalidated by the fact that most implementations
(to one extent or another) fail to fully conform.

To address the issue of "C is what intelligent users say it is", to an
extent I agree.  Equally (as with revisions of the OED), it's also
almost the other way round in that "C adapts to reflect what intelligent
users demand".  As a result, subsequent revisions of the standard tend
to take on board the best ideas of non-conforming implementations and,
as a result, many features from many different "C" compilers have ended
up as part of future standards.  That's as it should be.

Read Fowler/Burchfield Modern English Usage. Fowler makes no attempt
whatsoever to legislate what English should be, only what literate
people do. For example, Burchfield usefully notes that UK speakers
have FINALLY (as of the latest edition) given us an English
"construct" that is sorely needed: a reflexive pronoun that means
"himself or herself". "Themself" has been spotted by Burchfield:
"someone has hurt themself". Likewise, Adler's idiom makes perfect
sense.
It would be nice to think, however, that both compiler writers *and*
software engineers (try to) only go outside the standard deliberately,
and are fully aware of what that means.  As someone who has (over the
course of a twenty year career) had to deal with cross platform
development, environment changes, moves between 16, 32 and 64 bit
implementations and so on, life is *much* easier where that is built
into the assumptions of the developers from the start.

Of course, it also depends on the context.  If the code is *known* to be
used within quite limited environments and, perhaps more significantly,
if it's known to be short-lived*, this becomes less important.

* I have, however, known code that "will only be in use for the next
  couple of months" that suddenly became permanent.



In C, a pointer is something which can contain something which looks
like a pointer.  If it contains a valid pointer, it can be safely
dereferenced.  If it contains something which looks like a valid pointer
but isn't (isn't a pointer or isn't valid), it will cause a problem.

Your last statement is literally untrue in most cases, in C. There is
no runtime check, and there are cases of code that dereferences "bad"
pointers and gets away with it,.
Unfortunately, "register" is somewhat tricky concept in C.  There is no
obligation for the register keyword to do anything.  The "register"
storage-class specifier hints to the compiler that this storage
declaration declares an object (small-o) which the compiler should try
to ensure fast accesses to.  That request may be validly disregarded.
In some implementations (and originally, hence the wording) this may
be achieved by ensuring that it's kept in a register.  If an
architecture has a way of producing fast accesses which doesn't involve
registers, the compiler is perfectly entitled to emit code as a direct
result of "register" which has nothing to do with registers.

All very true but irrevelant to Adler's (Intuitionist) point: that one
test of a construct is whether we can construct a working runtime
model.

Whereas an earlier generation of C programmers (myself included)
graduated into C (and out of it in my case when I realized its
limitations) from assembler, many posters here started with C and may
have been crippled by it to the extent that they assault authors like
Schildt for speaking of stacks and heaps.
 
S

Seebs

Now I can play the game! (Gets up on soap box ...) I assert that a
function that takes a void * pointer and a size_t length to identify a
thing makes no sense whatsoever in the C standard, since length has no
meaning with respect to the void * pointer. Yet there are many such
functions that are also part of the C standard, such as memcpy(),
write(), etc.

write() is not part of the C standard.

And actually, no. size_t is the size-in-bytes, canonically, since that's
what sizeof(x) yields.
I would argue that alternatively we could eliminate this mixed message
of void both implicitly having a size and not having a size by changing
the C standard to give void a size, i.e. one. sizeof(void) == 1.
Nothing would break -- this would just add to the things that can be
expressed, in a way that is consistent with how library functions use
void * arguments. (The void type would still not be allowed by itself,
and so function(void) would still mean no arguments.) In fact, in the
evil gcc, n = sizeof(void); sets n to 1, and it seems to work fine.

It works, but it's dumbing things down -- it's encouraging sloppy thinking
about pointer types, and that ain't good.

-s
 

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,777
Messages
2,569,604
Members
45,224
Latest member
BettieToom

Latest Threads

Top