Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Keith Thompson <kst-u@xxxxxxx>
- Date: Fri, 11 Aug 2006 22:25:36 GMT
"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() orOK, I think I've heard some type of debate about this, I thought
realloc(). See section 7 of the comp.lang.c FAQ,
<http://www.c-faq.com/>, particularly questions 7.7b.
(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.)
[...]
Ok, it's your code, but I'm quite surprised that defining symbolicAs I've alluded, it partly depends on the scope. What I've found
constants would cause more problems than it would solve.
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.
Or you can use a macro and be careful about how you use it.
In this case, maybe a sizeof() would be better...
Probably so.
If someone else needs to maintain your code (and "someone else" couldEverything is local to a single 1000-line function for this data downloading
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>.
operation; any (many) calls out to my custom libraries don't care about
string lengths because they do a strlen() on the passed string pointer
on entry.
Yeah, apparently it only processes a char* at a time, and theThe first argument to qsort is:Then how does qsort() do it? I'm assuming now that it must just
(void *)curr_instrs + num_symbols
You can't do pointer arithmetic on a void* value. (Some compilers may
allow it; if you're using gcc, try "-ansi -pedantic -Wall -W", or
replace "-ansi" with "-std=c99").
use pointer arithmetic internally, because it doesn't seem to want or
recognize my typedef of a 128-character string:
typedef char instr_strs[128];
instr_strs *curr_instrs;
qsort behaves in a manner consistent with its specification. That's
all you really need to know. It needn't even be implemented in C, and
if it is, it's free to use compiler-specific extensions.
But if it's implemented in standard C (which is entirely possible), it
presumably would convert the void* arguments to char* before
performing arithmetic on them. (Since char* and void* have the same
representation, the conversion doesn't cost anything at run time.)
declaration of void* just prevents somebody from stupidly passing
the wrong starting point, or something...
void* is a generic pointer type. In fact, it's *the* generic pointer
type (pointer-to-object, actually; you can't portably use it for
pointers to functions). That's why qsort() uses it. (Earlier
versions of qsort(), before the 1989 ANSI standard, probably would
have used char*.)
I'm not sure what you mean by "it only processes a char* at a time".
qsort() works with whatever size of data you tell it to. It likely
uses memcpy() or something similar to copy data around within the
array.
[...]
Incidentally, a piece of code is either correct or not. The number ofTry telling that to a third-grade teacher grading tests...
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. Correctness is not statistical.
I'm not sure I see the point.
[...]
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.
Are you sure? Somehow, it seems like I tried it without the cast, and
got an error, but if that actually happened, it was years, hell, decades
ago.
Yes, I'm sure.
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.
A cast is, amongWell, OK, I just compiled it without the cast, and it came
other things, a promise to the compiler that you know what you're
doing, and will often inhibit warnings and error messages. In this
case, the argument will be implicitly converted to void* without the
cast (assuming you have a visible prototype for qsort() -- i.e., you
haven't forgotten the "#include <stdlib.h>".) The code is perfectly
correct either way, but the form with the cast is more "brittle". If
the cast had specified the wrong type, for example, the compiler
likely wouldn't have told you about the error.
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.
[...]
I haven't seen the full context of your code (or if I have, I'veActually, SEQUENCE POINTS!!!! Yes, I know now this is
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.
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).
[snip]
--
Keith Thompson (The_Other_Keith) kst-u@xxxxxxx <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
.
- Follow-Ups:
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Bill Reid
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- References:
- Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Bill Reid
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Barry Schwarz
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Bill Reid
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Keith Thompson
- Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- From: Bill Reid
- Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- Prev by Date: Re: passing a union's field to a function
- Next by Date: Re: passing a union's field to a function
- Previous by thread: Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- Next by thread: Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
- Index(es):
Relevant Pages
|