Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?




Keith Thompson <kst-u@xxxxxxx> wrote in message
news:lny7tuvrj4.fsf@xxxxxxxxxxxxxxxxxx
"Bill Reid" <hormelfree@xxxxxxxxxxxxxxxx> writes:
Keith Thompson <kst-u@xxxxxxx> wrote in message
news:lnzmebw00v.fsf@xxxxxxxxxxxxxxxxxx
"Bill Reid" <hormelfree@xxxxxxxxxxxxxxxx> writes:
[...]
I will make one comment: Don't cast the result of malloc() or
realloc(). See section 7 of the comp.lang.c FAQ,
<http://www.c-faq.com/>, particularly questions 7.7b.

OK, I think I've heard some type of debate about this, I thought
(based on the DOCUMENTATION THAT CAME WITH MY
FRIGGIN' DEVELOPMENT PACKAGE) that was what you
were supposed to do; it has seemed to work OK...

Then the DOCUMENTATION THAT CAME WITH YOUR FRIGGIN' DEVELOPMENT
PACKAGE is advising you to do something that's unnecessary and
potentially dangerous. (Unless it's intended to be called from C++,
which doesn't do implicit conversions to and from void* as freely as C
does, but that's a different language.)

Mmmmm, well it's actually a C++ package (with a lot of "Object Pascal"
crap laying around apparently just in a vain attempt to create a Microsoft
style monopoly--three guesses who made it), and I do call back and
forth between C and C++ and D----i, so maybe I DO want to keep
the "unneeded" casts...

To its credit, it seems to always issue warnings for any declarations
not in scope, so 7.7b has little to no practical relevance...

Ok, it's your code, but I'm quite surprised that defining symbolic
constants would cause more problems than it would solve.

As I've alluded, it partly depends on the scope. What I've found
the hard way is that you should really know EXACTLY what you
need AT THE MOST LOCAL LEVEL OF SCOPE. And I
found I kept forgetting what my global defines were, and I would
use an inappropriate one where I knew EXACTLY what I needed
RIGHT THERE. Among other problems...

Yes, one problem with macros is that they're not scoped.

If you want an integer constant (within the range of type int), there
is a trick you can use in C to limit it to the scope you want:

enum { WHATEVER = 128 };

It's arguably an abuse of the "enum" feature (you're doing it for the
sake of the constant, and not actualy using the type), but it does
work, and it's not an uncommon idiom.

I'm not sure about using that particular trick, but I will say I did a
major overhaul of my code a few years back where I ditched about
80% of my defines and replaced them with enums and have saved
tremendous amounts of wasted effort as a result.

Or you can use a macro and be careful about how you use it.

The real point is always that you always have to be careful and
there is no magic trick that will completely relieve you of the duty
to know what the hell you are doing.

In this case, maybe a sizeof() would be better...

Probably so.

If someone else needs to maintain your code (and "someone else" could
be you a year from now), it's not going to be obvious that the 128 in
this function corresponds to the 128 (or 127) in another function, but
the 128 in that function over there is just coincidental. There's a
good discussion at <http://c-faq.com/~scs/cclass/notes/sx9b.html>.

No offense but that is sooooo "old school" and "Mickey Mouse"...it
might have impressed me in 1975 writing a "hello world!" program in
my diappies, but I have much bigger fish to fry these days...I try to use
what tools are available in the best way possible, defines still have a
place in my code and always will, but I'm not kidding when I say
I got sick and tired of dealing with them, with one very important
exception; this is from the top of my c_inclds.h file that is included
in every C program I write:

#ifndef c_incldsH
#define c_incldsH

/* boolean boo-yah */
#define TRUE 1 /* what about negative logic? */
#define FALSE 0 /* not to mention situational ethics... */

After that there are about another 50 defines, including line length
maxs and crap like that, that I'd just as soon flush down the bit-crapper
than ever use again...

qsort behaves in a manner consistent with its specification. That's
all you really need to know.

Again, I may become a "victim" of the "documentation"...but what're
ya goin' to do? As I've said, if it gets the job done flawlessly after
being
compiled, I don't care what anything does...

Incidentally, a piece of code is either correct or not. The number of
times it "works" really doesn't prove anything. If your compiler
accepts some non-portable code, it's probably going to keep working
the same way indefinitely -- but it will fail the first time you
compile it with a different compiler, or with the same compiler and
different options.

Yeah, but I can do everything as "correctly" as possible and will
still have portability issues, so again, what're ya goin' to do?

Correctness is not statistical.

Try telling that to a third-grade teacher grading tests...

I'm not sure I see the point.

In all walks of life, and in so much of my own work, everything is
"graded". Some things are measurably "better" than others, you know,
like Japanese cars are better than American cars, because, you know,
they actually use this thing called "statistical quality control" and
other disciplines, while Americans don't so much, even though it was
invented here...

I value speed and flawless execution in computer programs, and
have implemented a methodology for some level of portability, modularity,
and maintainability, but those are secondary concerns...

Yeah, I noticed that, I just use (void *) because that's what
I thought qsort() wanted, and it definitely WORKS that way
(I've used qsort() dozens of times EXACTLY that way without
problems).

Yes, it works, but it's not necessary.

How about if I call it from C++ like you mentioned about malloc()?
I believe I actually do call malloc() in some xxx.cpp files...

Like most people, I'm a victim of experience: I just keep doing what
works...

As a general rule, casts
should be avoided unless they're actually required.

The question here would be: does qsort() require it? Here's the
documentation:

Syntax

#include <stdlib.h>
void qsort(void *base, size_t nelem, size_t width,
int (_USERENTRY *fcmp)(const void *, const void *));

and the example from the documentation:

int sort_function( const void *a, const void *b);
char list[5][4] = { "cat", "car", "cab", "cap", "can" };

int main(void)
{
int x;

qsort((void *)list, 5, sizeof(list[0]), sort_function);
for (x = 0; x < 5; x++)
printf("%s\n", list[x]);
return 0;
}

int sort_function( const void *a, const void *b)
{
return( strcmp((char *)a,(char *)b) );
}

Unlike some example documentation that I can think of, THAT one
actually works as advertised...but doesn't mean that the cast is
required...

Yes, it works with a cast. It also works without a cast, and there's
just no reason to use one.

What you quoted above is not *the* documentation for qsort(). You'll
find that in the C standard, and it doesn't say anything about casting
arguments.

Again, might be the C++ thing, or an urban legend or something...

Well, OK, I just compiled it without the cast, and it came
up clean. Then I immediately pasted the cast back in place, since
this is "production code", and from a perfectly practical standpoint,
the void* cast is 100% functional IN THIS CASE, so I'm loathe
to mess anything up...

Sure, if it already works, any change you make has a chance of
breaking something. But keep this in mind for any new code you write,
and when tracking down bugs in existing code. And if you're fixing a
piece of code anyway, you might as well remove any unnecessary casts
while you're at it; it will make the code more robust in the long run.

Unless I call it from C++?

I haven't seen the full context of your code (or if I have, I've
forgotten it). Your original code had

(void*)curr_instrs + num_symbols

which is illegal, because you can't perform pointer arithmetic on
void* (the cast applies to "curr_instrs", not to "curr_instrs +
num_symbols"). Pointer arithmetic, as you probably know, is scaled by
the size of the pointed-to type.

Actually, SEQUENCE POINTS!!!! Yes, I know now this is
wrong...

No, sequence points aren't involved. It's just a matter of operator
precedence (how an expression is parsed, and which operations apply to
which operands).

Oh, I thought that was "sequence points", but yeah, what I wrote
wouldn't work right.

Oh, while I've got you here, here's another issue I noticed that I'm
not sure about concerning realloc(). Here's the NON-documentation:

Syntax

#include <stdlib.h>
void *realloc(void *block, size_t size);

....

If block is a NULL pointer, realloc works just like malloc.

....

I read this years ago, and thought "Great, I don't necessarily have to
malloc something first, I can use realloc in a loop and the first pass
through the loop it'll just be like malloc."

Problem is, it didn't seem to work out that way, and I'm not sure
what I did wrong, but I think I tried a number of things, such as
explicitly initializing my memory pointer to NULL, and always got
an error...is it actually possible to use realloc() to act like malloc
with a NULL pointer?

---
William Ernest Reid



.



Relevant Pages

  • Re: problem with memcpy and pointers/arrays confusion - again
    ... this second method is known as an explicit conversion, or cast. ... The cast, in effect, tells the compiler: ... the malloc function. ... function taking a size_t as a parameter and returning a void pointer (i.e. ...
    (comp.lang.c)
  • Re: Why the compiler applies sign extension to unsigned data?
    ... I want the value of p to be made unsigned *before* the cast. ... want the cast to generate a sign extension. ... ULONG_PTR is ULONG and casting the pointer to ULONG_PTR first is the ... on the compiler and on the knowledge of the size of the ptr variable, ...
    (microsoft.public.development.device.drivers)
  • Re: Thank You -- Thomas J. Gritzan
    ... realloc() and free. ... My compiler chokes without using the cast for mallocor calloc. ... exit(1); ...
    (comp.lang.c)
  • Re: Problem with malloc
    ... In C you need not cast void pointers. ... void pointer to any other pointer type. ... >> If your compiler pukes at that then you need a new ...
    (comp.lang.c)
  • Re: Another ANSI C question about volatile
    ... > The cast is on the address of x. ... > lvalue of type 'pointer to volatile int'. ... > volatile, ... > that a compiler, needing to reread xp each time, would then ...
    (comp.lang.c)