Program crashes when running it outside dev environment

R

Richard Heathfield

pete said:
You need a cast if you're writing a function like strchr, strstr
or bsearch, which returns a pointer to an unqualified type,
which is derived from a parameter that points to a qualified type.

There's a good reason why those are library functions. :)

In general, casting away const is not something of which I can bring
myself to approve.
 
R

Richard Tobin

Richard Heathfield said:
I'd write it like this:

int compar(const void *vp1, const void *vp2)
{
const struct foo *p1 = vp1;
const struct foo *p2 = vp2;
return (p1->id > p2->id) - (p1->id < p2->id);
}

My version, unlike yours, is compatible with qsort.

Normally I'm not one to criticise pedantry, but really that is
irrelevant to the point at hand.
My version, unlike yours, doesn't risk overflow.

And again. Anyway, you have no reason to suppose that "id" can take
values that could cause overflow.
And my version, unlike yours, doesn't use
casts, and yet there is no constraint violation or syntax error.

If you're willing to change the program to use assignments instead of
casts, obviously casts aren't necessary. Hardly any C constructs are
necessary by that standard, and your assertion was vacuous.

Another example where a cast is needed is when converting one kind of
struct pointer to another (which is allowed under some circumstances).
But of course you can say that you wouldn't write the program like
that, or you would use a temporary void * variable. But it is again
an example of an expression that would be a constraint violation
without the the cast. And of course converting between pointers
and uintptr_t in C99.

-- Richard
 
D

David Tiktin

David Tiktin said:

Sure. Would you add a cast there? I wouldn't.

Yes, I would and do.
No, but they can be a nuisance at times! (And this, indeed, is one
such time.)


No. How does it fix the code? Does it remove the loss of
precision? Of course not!

Agreed it does not reomove the loss of precision. But the cast just
tells the compiler, "I know there's a loss of precision, and it's OK.
I accept that." The compiler respects our judgement when we clearly
state it. That's one of the reasons I program in C!
Add a comment to the code, explaining why no loss of precision is
involved.

The cast is, IMHO, better. My memory isn't what it used to be, and I
likely won't remember which for each of the hundreds of source files
I maintain which had which diagnostic which was really OK. With the
cast, I don't have to open the source file and find the comment every
damn time I build the thing! ;-)
So why hide it with a cast?

In the case at hand, nothing is being "hidden." I was warned and
determined that the danger I was being warned about did not exist. I
record that fact with a cast.

Really, your first instinct in the advice you gave was right: get rid
of all the warnings. I find it a little hard to believe either that
your code contains no casts or that your builds are full of warnings
you just ignore. (BTW, that's meant as a compliment ;-)

Dave
 
K

Keith Thompson

pete said:
I can't think of a concrete example of a cast which
causes a constraint
violation or syntax error when left out either, but diagnostics are
permitted for other code as well.

You need a cast if you're writing a function like strchr, strstr
or bsearch, which returns a pointer to an unqualified type,
which is derived from a parameter that points to a qualified type.

char *strstr(const char *s1, const char *s2)
{ [snip]
return (char *)s1;
}

I'd argue that that's a bug in the specification of strstr(), which
IMHO *should* be declared as:

const char *strstr(const char *s1, const char *s2)

I suppose it's declared the way it is to avoid breaking pre-ANSI code
that assigns the result of strstr to an unqualified char* object.
(The const qualifier could safely be added to the parameters without
breaking anything.) It's the same rationale as the one for not making
string literals const.

With strstr and friends, it's possible to discard the const qualifier
from a const char* with neither a cast nor a diagnostic. I think if
the language were being designed from scratch today, this would have
been done differently.
 
B

Ben Bacarisse

Richard Heathfield said:
David Tiktin said:


No, there are (rare) occasions when you do need a cast. But I don't know
of any occasion where you *need* a cast AND omitting it violates a
constraint or constitutes a syntax error.

Neither do I but what do you do in the recently discussed case of
pointers to pointers to types that lack a qualifier? For example, do
you use a cast to pass, say, a char ** to a function declared:

void f(const char *const *ccp);

This seems to me to be a case where the cast in:

char **p;
...
f((const char *const *)p);

is the best solution despite it being there simply to silence a
diagnostic. Of course the cast is not needed -- you could go via an
otherwise redundant void * variable, but it that really what you would
do?
 
C

CBFalconer

Richard said:
Normally I'm not one to criticise pedantry, but really that is
irrelevant to the point at hand.


And again. Anyway, you have no reason to suppose that "id" can
take values that could cause overflow.

IIRC the id field was declared as an int. Subtracting (or adding)
ints can always create overflows.

--
Please do not top-post. Your answer belongs after (or intermixed
with) the quoted material to which you reply, after snipping all
irrelevant material. See the following links:

<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/> (taming google)
<http://members.fortunecity.com/nnqweb/> (newusers)
 
I

Ian Collins

Keith said:
pete said:
Harald said:
Richard Heathfield wrote:
But I don't know
of any occasion where you *need* a cast AND omitting it violates a
constraint or constitutes a syntax error.
I can't think of a concrete example of a cast which
causes a constraint
violation or syntax error when left out either, but diagnostics are
permitted for other code as well.
You need a cast if you're writing a function like strchr, strstr
or bsearch, which returns a pointer to an unqualified type,
which is derived from a parameter that points to a qualified type.

char *strstr(const char *s1, const char *s2)
{ [snip]
return (char *)s1;
}

I'd argue that that's a bug in the specification of strstr(), which
IMHO *should* be declared as:

const char *strstr(const char *s1, const char *s2)

I suppose it's declared the way it is to avoid breaking pre-ANSI code
that assigns the result of strstr to an unqualified char* object.
(The const qualifier could safely be added to the parameters without
breaking anything.) It's the same rationale as the one for not making
string literals const.

With strstr and friends, it's possible to discard the const qualifier
from a const char* with neither a cast nor a diagnostic. I think if
the language were being designed from scratch today, this would have
been done differently.
<OT> The C++ solution was to provide two versions:

const char *strstr(const char *s1, const char *s2);
char *strstr(char *s1, const char *s2);

</OT>
 
R

Richard Heathfield

Richard Tobin said:
Normally I'm not one to criticise pedantry,

Whew! :)
but really that is irrelevant to the point at hand.

True, but since when did that stop any self-respecting clc-er?

If you're willing to change the program to use assignments instead of
casts, obviously casts aren't necessary.

Right. That's kind of my point. It is generally possible to fix broken
code without using casts.

<snip>
 
K

Keith Thompson

CBFalconer said:
AFAICS the only place you actually NEED a cast is when passing
variables to printf (and similar variadic) functions. Else they
will assume integers are passed.

No, the compiler will assume that each argument is of the (possibly
promoted) type of the expression, whatever that happens to be. This
type isn't necesarily int, or even an integer type. For a variadic
function, it just won't attempt to coerce the argument to the actual
parameter type, because it doesn't know it.

It's always *possible* to use printf without casting:

int n; /* want to print the address of n */
void *addr_of_n = &n;
printf("&n = %p\n", addr_of_n);

but it's cleaner just to use a cast:

int n;
printf("&n = %p\n", (void*)&n);

The only cases I can think of where a cast is actually required are
for a conversion between an integer type and a pointer type (not
involving a null pointer constant), or between a pointer-to-function
type and another pointer-to-function type. In both cases, the
conversion is allowed, but it cannot be done implicitly. (Conversion
from one pointer-to-object type to another can be done with two
implicit conversion, one from the source type to void* and another
from void* to the target type. Again, a cast is likely to be
cleaner.)
 
R

Richard Heathfield

David Tiktin said:
Agreed it does not reomove the loss of precision. But the cast just
tells the compiler, "I know there's a loss of precision, and it's OK.
I accept that."

C&V, please.

Really, your first instinct in the advice you gave was right: get rid
of all the warnings.

It's the right advice for a relative newcomer to C, I think. But so was
my suggestion about not adding casts, I think.
I find it a little hard to believe either that
your code contains no casts or that your builds are full of warnings
you just ignore. (BTW, that's meant as a compliment ;-)

It's a kind thought, for which I thank you. In fact, there are hardly
any casts in my code, and the ones that are there are generally
necessary ones. Any unnecessary ones tend to be hangovers from old
habits, which have so far survived occasional sporadic bursts of
cleanup.

As for warnings, the vast majority I get (at least in gcc) are from the
code pattern T object = {0}; - and I haven't yet found a *good*
workaround for getting rid of those. If it were topical, I'd invite
suggestions, but it isn't so I won't.
 
R

Richard Heathfield

Ben Bacarisse said:
Neither do I but what do you do in the recently discussed case of
pointers to pointers to types that lack a qualifier?

I have two answers to this, each based on a different interpretation of
"you".

In the general case (generic "you"), I would answer that, if there is no
escaping the API[1], then perhaps the cast would be the wisest course,
given that you are not changing the type, and you are *adding*
constness rather than taking it away.

In the specific case ("you" as in me), my answer is that I Don't Do
That! :) That is, I cannot recall ever having to face that problem in
real code, and neither do I anticipate doing so.

<snip>

[1] For example: find the author of f(), and say to him "See this
function? See this keyboard? See this pointy stick?"
 
R

Richard Heathfield

CBFalconer said:
IIRC the id field was declared as an int. Subtracting (or adding)
ints can always create overflows.

To be fair to RT, I think his point was that the problem domain might
not be exposed to that kind of problem - for example, if the values
were all known to be in the range -10000 to +10000. It is impossible to
find two values in that range such that subtracting one from the other
will overflow an int.
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:


I have two answers to this, each based on a different interpretation of
"you".

I should have said "what do you advice" since the situation came to
mind simply as a counter example to the rather emphatic:

RH> 3) fix every single diagnostic message, and *never* with a cast
In the general case (generic "you"), I would answer that, if there is no
escaping the API[1], then perhaps the cast would be the wisest course,
given that you are not changing the type, and you are *adding*
constness rather than taking it away.

Of course, hence the example of adding constness.

This may be too big a can of worms to open up, but I would be
interested to know why you consider such double indirect constness
such a bad idea. Is it just that C does not deal with such types
easily and therefore you prefer to avoid them (my only reason for
avoiding them), or is there a more subtle technical reason why some
constness is good while this one is bad?
 
R

Richard Heathfield

Ben Bacarisse said:
Is it just that C does not deal with such types
easily and therefore you prefer to avoid them (my only reason for
avoiding them),

Yes. I'm good at avoiding C features that I don't like. :)
 
J

Johan Bengtsson

z said:
I use Visual C 2005 to develop my programs. One in particular is
crashing in very specific and hard to replicate situations, made worse
by the fact it only crashes when run -outside- the dev - as an exe,
not from the Debug option. If I try to launch the debug on the
crashing program, it'll close before the debugger opens. Any
suggestions as to how I should proceed? Thanks in advance.
Does it fail when the debug version is run outside the environment, or
is it the release version that fails?
If it is the release version, a possible suggestion is that you actually
can debug the release version as well, but some things might be *very*
strange in the debugger (like freshly assigned variables keeping the old
value and so on because it is not stored to memory yet, understanding of
assembler is a plus in those cases)

To pinpoint an error location outside of the environment could be
possible doing either of those:
for GUI apps:
MessageBox(...);
MessageBeep(...);
for console apps:
printf(...); or fprintf(stderr,...);
(replace ... with proper code...) Of course the first two are very
platform specific.

When all else fail I usually put a pair of those statements in
suspected top level functions, one at the beginning and one at the end
of each function like this:

void somefunction(void)
{
MessageBox("somefunction...","",MB_OK|MB_ICONINFORMATION);

/* the body of the function */

MessageBox("...somefunction","",MB_OK|MB_ICONINFORMATION);
}

This obviously won't work well for functions called lots of times unless
they crash fairly fast in program execution.
When a function is pinpointed I put in more message boxes in that
function in key places and so on...

For console apps fprintf(stderr,...) using the same basic technique
could be used instead, I don't know if it would be a good idea to add a
fflush(stderr) to each call... Someone else here could probably answer
that if necessary.


If it just fails strangely and sometimes inside system functions it
might be overwritten memory or some such problem. I use to put
statements like this at key points in my program to find the real reason:
ASSERT(AfxCheckMemory());
(ASSERT only works in debug version however, if you want to do this in
the release version you have to alter the code to some similar)
AfxCheckMemory() is probably very microsoft specific and not at all
portable, but you don't want to keep them there once the problem is
found anyway because they takes some time to execute.

Put one of those lines immediately before the line that crashes the
program. If the ASSERT fails you have a memory corruption problem
somewhere in your program.
If that is the case I put pairs of those in each top level suspected
function. If it crashes on the top one the problem is elsewhere, if it
crashes on the bottom one it is in that function...

If you have multiple threads also it might be a real nightmare to
debug... Try to shut of parts not needed.
 
R

Richard Tobin

IIRC the id field was declared as an int. Subtracting (or adding)
ints can always create overflows.
[/QUOTE]
To be fair to RT, I think his point was that the problem domain might
not be exposed to that kind of problem - for example, if the values
were all known to be in the range -10000 to +10000. It is impossible to
find two values in that range such that subtracting one from the other
will overflow an int.

Or, more simply, if you know they're always non-negative.

-- Richard
 
T

Thad Smith

Ian said:
Keith said:
pete said:
Harald van =?UTF-8?B?RMSzaw==?= wrote:

char *strstr(const char *s1, const char *s2)
{
[snip]

return (char *)s1;
}

I'd argue that that's a bug in the specification of strstr(), which
IMHO *should* be declared as:

const char *strstr(const char *s1, const char *s2)

I suppose it's declared the way it is to avoid breaking pre-ANSI code
that assigns the result of strstr to an unqualified char* object.
(The const qualifier could safely be added to the parameters without
breaking anything.)

That depends on what you need. If you are passing a non-const array and
plan to modify the array based on the return value, a non-const return
type is appropriate.
<OT> The C++ solution was to provide two versions:

const char *strstr(const char *s1, const char *s2);
char *strstr(char *s1, const char *s2);

</OT>

Yes, these are two separate use cases with regard to qualification of
the parameter and return values. In C, we could do that with two
different function names, but if one works for both, we gain little for
the increased confusion factor.
 
K

Keith Thompson

Thad Smith said:
Ian Collins wrote: [...]
<OT> The C++ solution was to provide two versions:
const char *strstr(const char *s1, const char *s2);
char *strstr(char *s1, const char *s2);
</OT>

Yes, these are two separate use cases with regard to qualification of
the parameter and return values. In C, we could do that with two
different function names, but if one works for both, we gain little
for the increased confusion factor.

What we would gain would be const safety. The current inferface
allows constness to be thrown away with no diagnostics from the
compiler. But then as long as string literals aren't const,
maintaining const consistency requires a lot of care by the programmer
anyway.

Probably the strstr() interface was established before the "const"
keyword was added to the language, and adding a second function with a
distinct name was considered too confusing. But we do pay a cost for
the simplicity of having a single function. (If overloading were ever
added to C, splitting the strstr function as C++ did would be a good
idea, but I'm not holding my breath.)
 
P

pete

Keith Thompson wrote:
Probably the strstr() interface was established before the "const"
keyword was added to the language,

I've never seen a version of strstr
that didn't have a (const char *) type parameter.
 
K

Keith Thompson

pete said:
I've never seen a version of strstr
that didn't have a (const char *) type parameter.

I see that K&R1 doesn't mention strstr, but it does talk about strcat,
strcmp, strcpy, and strlen (and something called strsave, which is
equivalent to strdup, but is presented as an example). This was
before the "const" keyword was added to the language.
 

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
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top