To assert or not to assert...

N

Nick Keighley

If I read you correctly, it sounds like nowadays assert is the wrong
level of abstraction for checking against dereferenced NULL pointers,

I'm not sure I read that in what he said
due to operating system maturity.  That sounds reasonable to me.  Was
there any time when it was needed to provide this kind of context?

crashing is pretty traditional. The C library assumes you pass it the
right stuff. You put the asserts in *your* code.

I was under the impression that assert was for developers, not
computer users.  My understanding is that assert is NDEBUGed out
before it gets to the computer user.

this is a fairly common practice but FAR FAR from being universal.
Many megabits have been ruthlessly expended on clc (and elsewhere)
arguing if assert()s should be NDEBUGed. That Microsoft's compilers do
this by default doesn't we have to imitate them.
 If assert is being used as
communicating errors to users, that's a different can of worms.  And
this was a topic covered in the other couple of threads I read on
assert.

assert() is a pretty crude instrement for communicating with users.
The user should never see an assert message. OTOH I don't want my
program running on with its fundamental assumptions left in tatters. I
tend to use my own assert-like macros that write to log files before
dieing. At least they can email me the logfile.

I'm curious, do you or any of the other coders around here have used
'assert' at all in your C code within the last year?

yes. In noddy tools. As preconditions in functions. As crude test
harnesses. But I tend to prefer my own assert-like thingies. So I
*know* which ones are left in the shippable version. That they write
to a log file. Preconditions might be left as assert() (though I
suppose those should be PRE_CONDITION or something).

 Until I stumbled
across some assert thread looking for something else, I never
considered using assert in my code.  Unless I know how to use 'assert'
right, I really don't want to use it at all.

I'm not sure ther eis a "right". Look up Design by Contract. assert()s
can be a cheap and cheerful way of asserting a functions's
preconditions. If you use assert()s as preconditions quite copiously
you'll be surprised how often you stumble into them.
 
P

Phil Carmody

bart.c said:
You mean, between "assertion error: mugwump.c(42) x>0" and SIGCHOKE. The
former can help narrow down the error more quickly, and might suggest an
interim workaround for the user.

I used to add even more explanation to my asserts for a while, using the
following kind of code.

int extract(int n, struct thing* p)
{
assert(p.buf && p.n>=n && "did we not sync() properly, or is this a stale copy?!?");
}

I never knew whether my assertion would fire days after writing or
years after writing (I have some hobby projects that are in nearly
their tenth year now), so wanted to make the maintenance task as
smooth as possible.

Of course, the above does little more than an annotative comment,
but I have no problem with it being squirted out to stderr as it
happens.

Phil
 
N

Nick Keighley

Well, my context has been cut off three times in this thread.  

meaning what?
First by
Ian.  I didn't mind that so much.  Second by a Rui, who thinks I was
advertising a book.  Third by Keith, because bandwidth cannot support my
comments and his girth.

Anyways, this is how Plauger begins with assert:

$ ls
XASSERT.C
$ cat XASSERT.C
/* _Assert function */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

void _Assert(char *mesg)
        {       /* print assertion message and abort */
        fputs(mesg, stderr);
        fputs(" -- assertion failed\n", stderr);
        abort();
        }
$

Equally important is how Plauger designs his library:

$ pwd
/home/dan/source/CLIB
$ ls
ASSERT  ERRNO     LOCALE      SETJMP  STDLIB  _TEST     _UNIXVAX
CTYPE   FLOAT     MATH        SIGNAL  STRING  TIME
_DUMMY  _HEADERS  README.TXT  STDIO   _TC86   _UNIX68K

There's alot I have to work out with this yet, but the role of assert
finds no better explanation with the 3 amigos who cut me off.

Legal stuff after sig.

WTF?

why did you include Plauger's entire license agreement in your post?

--
Uno

[Rui, you can stop reading.]

$ cat README.TXT
                   STANDARD C LIBRARY CODE DISK V. 2.0

This diskette contains all the source code from ``The Standard C Library,''
by P.J. Plauger (Englewood Cliffs, N.J.: Prentice-Hall, 1992). It corrects
a number of errors reported after publication. Hence, the code may differ
from the book in small ways.

<snip yards more>
 
N

Nick Keighley

Well, my context has been cut off three times in this thread.  

meaning what?




First by
Ian.  I didn't mind that so much.  Second by a Rui, who thinks I was
advertising a book.  Third by Keith, because bandwidth cannot support my
comments and his girth.
Anyways, this is how Plauger begins with assert:
$ ls
XASSERT.C
$ cat XASSERT.C
/* _Assert function */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
void _Assert(char *mesg)
        {       /* print assertion message and abort */
        fputs(mesg, stderr);
        fputs(" -- assertion failed\n", stderr);
        abort();
        }
$
Equally important is how Plauger designs his library:
$ pwd
/home/dan/source/CLIB
$ ls
ASSERT  ERRNO     LOCALE      SETJMP  STDLIB  _TEST     _UNIXVAX
CTYPE   FLOAT     MATH        SIGNAL  STRING  TIME
_DUMMY  _HEADERS  README.TXT  STDIO   _TC86   _UNIX68K
There's alot I have to work out with this yet, but the role of assert
finds no better explanation with the 3 amigos who cut me off.
Legal stuff after sig.

WTF?

why did you include Plauger's entire license agreement in your post?
[Rui, you can stop reading.]
$ cat README.TXT
                   STANDARD C LIBRARY CODE DISK V. 2.0
This diskette contains all the source code from ``The Standard C Library,''
by P.J. Plauger (Englewood Cliffs, N.J.: Prentice-Hall, 1992). It corrects
a number of errors reported after publication. Hence, the code may differ
from the book in small ways.

<snip yards more>

ah, sorry I should have read the rest of the thread to get some
context. I see now you were called out for posting a lot of
unnecessary material so you now compound your mistake by doing it
again.

You are an idiot.
 
K

Keith Thompson

Uno said:
Well, my context has been cut off three times in this thread. First by
Ian. I didn't mind that so much. Second by a Rui, who thinks I was
advertising a book. Third by Keith, because bandwidth cannot support my
comments and his girth.
[...]

So when you're criticized for excessive quoting, you ignore the
reasons for the criticism, insult me, and deliberately do it again.

Did it occur to you that your critics might have a valid point?

You might consider rethinking the way you interact with other
human beings.
 
I

ImpalerCore

I'm not sure I read that in what he said

Do you use assert or some other precondition macro that aborts to
check arguments for NULL pointers in the functions that you write at
all?
crashing is pretty traditional. The C library assumes you pass it the
right stuff. You put the asserts in *your* code.

If the C standard library doesn't populate their library with asserts,
why should I populate my library with asserts at all?
this is a fairly common practice but FAR FAR from being universal.
Many megabits have been ruthlessly expended on clc (and elsewhere)
arguing if assert()s should be NDEBUGed. That Microsoft's compilers do
this by default doesn't we have to imitate them.

And the disagreement leaves me with the impression that the assert
mechanism wasn't designed properly in the first place since no one can
seem to agree on what exactly it or NDEBUG is intended for. Hence my
reservation for populating asserts as is in code that I write. The
concept of assert as a precondition I want to incorporate, but how
exactly to do it still seems to elude me, probably because there isn't
a de-facto standard for this issue.
assert() is a pretty crude instrement for communicating with users.
The user should never see an assert message. OTOH I don't want my
program running on with its fundamental assumptions left in tatters. I
tend to use my own assert-like macros that write to log files before
dieing. At least they can email me the logfile.

While that is perfectly understandable for end-user applications that
interface with people, does it also apply at the library developer
level? Pretend you're making a library, do you foresee the library
being responsible for generating logfiles for internal preconditions
that failed? I've looked at a small set of open source libraries. I
noticed libavl has some asserts sprinkled about, but I didn't come
across other libraries that had them in my small sample.

For example, let's say that I have a generic array interface
'c_array'. I create an array, but don't check whether it's really
been allocated.

c_array_t* array = c_array_new( int, 1000 );
/* Let's assume that array is NULL because of memory issues */

for ( i = 0; i < c_array_size( array ); ++i )
....

I'm getting more and more comfortable with letting 'c_array_size' bomb
because it tries to access a member of a struct from a NULL pointer,
without an assert message because this is the behavior that the
standard C library uses.
yes. In noddy tools. As preconditions in functions. As crude test
harnesses. But I tend to prefer my own assert-like thingies. So I
*know* which ones are left in the shippable version. That they write
to a log file. Preconditions might be left as assert() (though I
suppose those should be PRE_CONDITION or something).

That is a fine viewpoint. If you have released code where you can
turn on preconditions to troubleshoot problems that users find, that
is not the job for assert in the way it's usually presented. I think
that 'assert' as a concept is very useful idea, but I haven't settled
how I want to go about implementing it.
I'm not sure ther eis a "right". Look up Design by Contract. assert()s
can be a cheap and cheerful way of asserting a functions's
preconditions. If you use assert()s as preconditions quite copiously
you'll be surprised how often you stumble into them.

I have spent a decent amount of time reading some online literature of
design by contract as the result of your prodding a while back. I'm
still interested in putting preconditions in some form in the library
I'm writing, but still mulling over how to do it.

I have investigated trying to use some unit testing framework for my
library as well, but it's been slow going as I really have no
experience in test, and there are only so many hours in the day so it
seems the first thing I cut. Do you have any recommendation for a C
framework? Of the frameworks I've investigated, the CUnit one seems
to appeal to me the most. Is there a C open source project that you
would recommend that in your opinion implements a good unit testing
framework that I can glean some knowledge from?

Thanks again,
John D.
 
E

Eric Sosman

If the C standard library doesn't populate their library with asserts,
why should I populate my library with asserts at all?

Because your library is less thoroughly tested.
 
S

Seebs

why did you include Plauger's entire license agreement in your post?

Judging by the writing style, "Uno" is yet another rename of the user
formerly known as "frank", formerly known as... I dunno, he changes his
name every few months, but he's pretty recognizeable.

-s
 
I

ImpalerCore

     Because your library is less thoroughly tested.

I can certainly agree with that understatement (as in my library is a
whole *lot* less tested). Maybe I should think of assert as the
developer's training wheels, used to keep the developer balanced until
the library matures to a point that the majority of bugs have been
worked out and that it has a test framework to torture it and verify
its behavior. At some point, maybe I could take the training wheels
off. But for now, I'm definitely in the training wheels stage.

In my case since I do not have a test framework to verify library
behavior, perhaps the role of assert is to function as a stopgap until
a more format test suite is in place.

Thanks for the comment,
John D.
 
E

Eric Sosman

I can certainly agree with that understatement (as in my library is a
whole *lot* less tested). Maybe I should think of assert as the
developer's training wheels, used to keep the developer balanced until
the library matures to a point that the majority of bugs have been
worked out and that it has a test framework to torture it and verify
its behavior. At some point, maybe I could take the training wheels
off. But for now, I'm definitely in the training wheels stage.

Hadn't thought of the training wheels analogy -- but I'm not sure
I agree with it, either. In the early going, assert() can truly be
a lot like training wheels, helping you get your code to stop falling
over. Once you've achieved stability, though, I don't think assert()
should fall completely out of the repertoire -- if nothing else, it
can be a guard against mistakes introduced by changes to other parts
of the code. If you register each Wingding in a hash table when it
arrives, then work on it for a while and de-register it when the
response goes out, you may "know" that (1) an incoming Wingding is
*not* in the hash table and (2) and an outgoing Wingding *is* there.
If this property is important, a couple assert() macros would not be
amiss. Even if it's not "important" but would prompt a "What the?"
if it somehow didn't hold, assert() can be the canary in the mine,
alerting you that all's not well.
In my case since I do not have a test framework to verify library
behavior, perhaps the role of assert is to function as a stopgap until
a more format test suite is in place.

... which leads back to the "Should released code be NDEBUG?"
debate. Last time around, smart people argued vehemently on both
sides -- which should tell you something about the maturity of what
we're pleased to call "software engineering" ...
 
G

Gene

I stumbled across a couple assert threads from a while ago.  I seem to
have a hard time figuring out how to use assert properly, and I go
back and forth over how best to represent errors from a library's
perspective.  From what I've gathered, assert is intended to catch
programming errors, but I don't really know what that means in the
context when writing a library.

There are three main errors that I try to handle.

1. Memory allocation faults.

These faults are caused when malloc, realloc, or calloc fails.  There
are several methods that this can be communicated to the user.  For
functions that allocate structures, the return value represents either
the allocated object if successful or returns NULL if allocation
failed.  The caller of the function is responsible for handling the
result.

\code snippet
c_array_t* numbers = NULL;

numbers = c_array_new( int, 20 );
if ( !numbers )
{
  /* User specified method to handle error. */
  fprintf( stderr, "c_array_new: failed to allocate array 'numbers'!
\n" );
  return EXIT_FAILURE;

}

...
\endcode

In this scenario, I know that I definitely don't want to assert on a
memory fault at the library level, because in general the user may be
able to recover from the situation, and I want to give him that
chance.

However, there are other functions that may invoke a buffer expansion
as part of the operation, requiring a call to malloc or realloc that
may fail.  This needs to be communicated back to the user somehow.
Here is an example.

void gc_array_push_back( c_array_t* array, void* object, size_t
type_sz );
#define c_array_push_back( array, object, type ) \
  (gc_array_push_back( (array), (object), sizeof( type ) ))

\question
Should the internals of 'gc_array_push_back' use assert to check for
null array pointers.?

Consider two possible methods to verify the array parameter.

void gc_array_push_back( c_array_t* array, void* object, size_t
type_sz )
{
  /* variable decls */

  assert( array != NULL );

  /* push_back code */

}

vs

void gc_array_push_back( c_array_t* array, void* object, size_t
type_sz )
{
  /* variable decls */

  if ( array )
  {
    /* push_back code */
  }}

\endquestion

Most of the time, an array NULL pointer is likely an error, so assert
would help catch programming errors.  However, I can't guarantee that
there isn't a user that would have a valid use case for having a null
array pointer, perhaps if it's considered as an empty array in another
structure.  So in this case, I feel that the 'if ( array )' construct
feels right.

Another question within the same context of the 'c_array_push_back'
function is how to communicate an allocation failure if the array
needs more memory, but the allocation fails.  At the minimum, I want
to make sure that I don't lose any of the contents of the array
buffer, so that the array contents remain the same.  There seem to be
several methods to communicate that an allocation error in this case.

A.  Modify 'gc_array_push_back' to respond with an error code via the
return value (or as an additional argument to the function, but I
really prefer not to use that style of interface).

This is a common scheme that is used and recommended often, and for
good reason.  The main drawback is that sometimes there is competition
for the return value slot (not in the gc_array_push_back function's
case since it returns void, but in other functions).  If I want to
carry the error code and something else, I need to write a custom
struct and it complicates the interface somewhat.

struct c_array_return
{
  <data_type> data;
  int error;

}

The other issue is that there can be conflicts between interpretation
of the return value.  For example, if I make a copy of an array.

\code snippet
c_array_t* c_array_copy( c_array_t* array )
{
  c_array_t* copy = NULL;

  if ( array )
  {
    /* copy array */
  }

  return copy;}

\endcode

If I allow arrays that are NULL pointers, then checking the return
value of c_array_copy for NULL is troublesome because I can't
distinguish whether the parameter 'array' is NULL or if the allocation
failed, which may be an important distinction.

B.  Use some global variable that users should set before the
operation and check after the operation, akin to setting errno to
ENOMEM.

One of the issues brought up before is that ENOMEM isn't portable, so
it's not a reliable mechanism to use in of itself.  However, the
concept is usable provided that you maintain the global state
yourself.

In my case, I have my library use a wrapper that maintains a global
state that is accessed using a macro 'c_enomem'.  It functions
similarly to errno, but I have control over what it does provided that
my library calls my wrapper.

\code snippet
/* A flag that signals an out-of-memory error has occurred. */
static c_bool gc_private_allocator_enomem = FALSE;

c_bool* gc_error_not_enough_memory( void )
{
  return &gc_private_allocator_enomem;

}

#define c_enomem (*gc_error_not_enough_memory())

void* c_malloc( size_t size )
{
  void* mem = NULL;

  if ( size )
  {
    mem = gc_private_allocator_ftable.malloc( size );
    if ( !mem ) {
      gc_private_allocator_enomem = TRUE;
    }
  }

  return mem;}

\endcode

With this kind of mechanism in place, I can do something like the
following:

\code snippet
c_array_t* numbers = NULL;
int n;

numbers = c_array_new( int, 20 );
/* Fill up numbers array */

c_enomem = FALSE;
c_array_push_back( numbers, &n, int );
if ( c_enomem ) {
  fprintf( stderr, "c_array_push_back: allocation failure!\n" );
  /* Try to recover or save gracefully if desired */}

\endcode

This scenario also has its drawbacks, but it's the poison that I've
chosen particular for functions that would instead have to return
something in addition to an error code.

These are the main two error handling schemes that I'm familiar with
that has the granularity to handle function level out-of-memory
conditions.  Signals and callback handlers are also useful tools, but
I've not been able to figure out a framework that seems to work at
this level.  I've only used them as general error handlers if any
allocation fails, rather than at specific locations.

2. Invalid arguments

This is where I really struggle with what is assertable and what is
left to the user is left to blow up.

Take a function to erase an element out of an array.

void gc_array_erase( c_array_t* array, size_t pos )
{
  if ( array )
  {
    /* what to assert if anything */
    if ( pos < array->size )
    {
      /* erase the element at index 'pos' */
    }
  }

}

Does the condition 'pos < size' constitute a good assert candidate?
There is no possible scenario where a pos >= array->size would ever do
anything, but does the crime fit the punishment of abort in a library
like this?  If not, is the silent treatment ok, or should an out-of-
range error be communicated back somehow?  I can't see the pros and
cons enough to make a decision and stick to it.

I could see maybe having another layer of assert that takes the middle
ground.  If the user wants to assert for conditions when pos is larger
than the array size and other invalid arguments, the library could
have something like the following.

void gc_array_erase( c_array_t* array, size_t pos )
{
  if ( array )
  {
    safe_assert( pos < array->size );
    if ( pos < array->size )
    {
      /* erase the element at index 'pos' */
    }
  }

}

This would give the users of the library some semblance of choice on
how strict to apply the assert checking mechanism.

3.  Programming errors

At the library level, do I assert things within my library interface
that the user may have messed up?  Take for example inserting an
object into an array in a sorted fashion.

\code snippet
void gc_array_insert_sorted( c_array_t* array, void* object,
c_compare_function_t cmp_fn, size_t type_sz )
{
  if ( array )
  {
    assert( c_is_array_sorted( array, cmp_fn ) );
    ...
  }}

\endcode

In this scenario, I have a function that verifies that all the
elements are in sorted order.  Is this an assertable offense?  It's
certainly possible that the user may want to insert something sorted
in the array even though the array itself is not sorted.  I don't feel
that I have the right for my library to demand that the array is
sorted via assert, even if the constraint of having a sorted array is
violated.  This could be another 'safe_assert' or another level of
assert to verify this property.

There are cases that assert seems to be a good use for.  Particularly,
if I have a valid array pointer, it's buffer better be valid too.

\code snippet
void gc_array_insert_sorted( c_array_t* array, void* object,
c_compare_function_t cmp_fn, size_t type_sz )
{
  if ( array )
  {
    assert( array->buffer != NULL );
  }}

\endcode

This seems like a great candidate to be used in an assert, since I
specifically designed the interface to always have at least one
element allocated (the 'array->size' can still be zero though if no
elements are inserted into the array).

The last thing is whether it's recommended or not to append a string
to the assert macro to help provide flavor to the condition.
Something like

\code
assert( pos < array->size && "pos outside range: >= array->size" );
\endcode

Some things I've been pondering as of late.

The two things you're interested in -- library runtime error handling
and assertions -- are completely different as metaphors and in their
purposes. Mixing them will be confusing as a minimum.

Assertions are both documentation and debugging aids that are about
code invariants (See for example D. Griess _The Science of Computer
Programming_ on this topic). At once they document invariants and
tell you at run time if what you _thought_ was invariant really is
not; i.e. there is a gap between your mental model of the program and
what it's actually doing. An example of an invariant is that
successive pairs of elements in a sorted list are identically
ordered. If you ever find a pair that's out of order, your assertion
of "sortedness" is obviously wrong.

Runtime error checks are about assumptions rather than invariants.
You are checking assumptions about whether the caller provided valid
arguments, the system has enough memory, that I/O operations
succeeded, etc. For these purposes, you want to give the caller lots
of freedom to deal with the assumption violation in the best possible
way: report, repair, resume, recover, die gracefully are a few
options. Error callbacks are a common approach.

Cheers
 
I

ImpalerCore

     Hadn't thought of the training wheels analogy -- but I'm not sure
I agree with it, either.  In the early going, assert() can truly be
a lot like training wheels, helping you get your code to stop falling
over.  Once you've achieved stability, though, I don't think assert()
should fall completely out of the repertoire -- if nothing else, it
can be a guard against mistakes introduced by changes to other parts
of the code.  If you register each Wingding in a hash table when it
arrives, then work on it for a while and de-register it when the
response goes out, you may "know" that (1) an incoming Wingding is
*not* in the hash table and (2) and an outgoing Wingding *is* there.
If this property is important, a couple assert() macros would not be
amiss.  Even if it's not "important" but would prompt a "What the?"
if it somehow didn't hold, assert() can be the canary in the mine,
alerting you that all's not well.

Well, I also had a diaper analogy, but I decided not to go there.
     ... which leads back to the "Should released code be NDEBUG?"
debate.  Last time around, smart people argued vehemently on both
sides -- which should tell you something about the maturity of what
we're pleased to call "software engineering" ...

I think it depends on the amount of trust that you have in the
perceived quality of the library and its test framework. For example,
I'm willing to trust that the gcc implementation of the standard C
library is good from the point that so many people are using it and it
has an extensive test suite. The fact they feel assert (or any
precondition that bombs macro) is not needed in their framework feels
justified imo for those two reasons. Because of those resources,
assert doesn't really buy them anything more than what their test code
base and community already provides.

For the lowly developer who is trying to make something new, I can
definitely see that assert can provide a lot of bang for the buck sort
to speak. If I was using a library that made use of assert, I would
want to include NDEBUG for as long as I perceived that using the
library had an unacceptable level of risk, and I don't mind the
trouble dealing with users when the application program using the
library bombed. The amount is risk in using that library goes down as
the number of users and the quality of the test framework goes up. As
long as the application developer can make that decision by defining
NDEBUG when they compile my library or not, I'm starting to think it's
okay to use assert in a library environment.

Best regards,
John D.
 
I

ImpalerCore

[snip]


The two things you're interested in -- library runtime error handling
and assertions -- are completely different as metaphors and in their
purposes.  Mixing them will be confusing as a minimum.

Yeah, I have had trouble understanding what the distinctions are.
Assertions are both documentation and debugging aids that are about
code invariants (See for example D. Griess _The Science of Computer
Programming_ on this topic).  At once they document invariants and
tell you at run time if what you _thought_ was invariant really is
not; i.e. there is a gap between your mental model of the program and
what it's actually doing.  An example of an invariant is that
successive pairs of elements in a sorted list are identically
ordered.  If you ever find a pair that's out of order, your assertion
of "sortedness" is obviously wrong.

This example is pretty clear to me.
Runtime error checks are about assumptions rather than invariants.
You are checking assumptions about whether the caller provided valid
arguments, the system has enough memory, that I/O operations
succeeded, etc.  For these purposes, you want to give the caller lots
of freedom to deal with the assumption violation in the best possible
way: report, repair, resume, recover, die gracefully are a few
options.  Error callbacks are a common approach.

Let me pose my current conundrum. What do you think is the best way
to handle a user passing a null structure to a library function that
uses a member.

For example, I have a c_array_size that takes a 'struct c_array'
pointer. I call c_array_size( NULL ). Which of the following do you
think in your opinion is the best implementation?

1. Do nothing.

\code
size_t c_array_size( struct c_array* array )
{
return array->size;
}
\endcode

2. Assert something.

\code
size_t c_array_size( struct c_array* array )
{
assert( array != NULL );
return array->size;
}
\endcode

3. Have some other error handling.

\code
size_t c_array_size( struct c_array* array )
{
size_t result = 0;

if ( array ) {
result = array->size;
} else {
/* Insert custom error handling here. */
errno = EINVAL;
}

return result;
}
\endcode

How would you classify a user passing a NULL argument to this kind of
library function? An error in an invariant, a library runtime error,
or just the library user being stupid (hence do nothing?). It seems
like it could be one or the other depending on how you look at it.

Best regards,
John D.
 
U

Uno

Keith said:
Uno said:
Well, my context has been cut off three times in this thread. First by
Ian. I didn't mind that so much. Second by a Rui, who thinks I was
advertising a book. Third by Keith, because bandwidth cannot support my
comments and his girth.
[...]

So when you're criticized for excessive quoting, you ignore the
reasons for the criticism, insult me, and deliberately do it again.

Did it occur to you that your critics might have a valid point?

You might consider rethinking the way you interact with other
human beings.

Keith,

I apologize. I wasn't cut off thrice, but I thought I wasn't getting
through something that I thought was germane.

My critics *almost always* have a valid point, but you have a differing
role among them. I would say that you're the de facto editor in chief
in c.l.c., by virtue of your knowledge, experience, and closeness to the
C development process.

I'm always re-thinking how I deal with people, so you don't have to
worry about that. I was realworld-busy during much of the meaty portion
of this thread; I probably haven't read beyond the 12th message. I
thought it was a quality post, and as first respondent chose to
reproduce the whole post which has been called "absurdly long" by
respondents. I don't see much difference between calling something
"absurdly long" or "just plain fat."

I think OP is still challenging this forum with innovative questions. I
lack the technical prerequisites in C to advise him, but I thought I
would give him some cloudcover.

Cheers,
 
I

ImpalerCore

Prove it.

I think the point they were trying to make is that the cumulative
amount of work made for other people reading your 2-3 line response
could have been significantly reduced by a little judicial snipping on
your part. Unfortunately that kind of criticism is often flavored
with an assortment of spicy words that don't digest in the best
possible way.

Personally I don't care that much about post edicate. But I still try
to make an effort to format responses, especially since the formatting
seems to have a positive correlation with getting people smarter and
more experienced than me to respond.

Best regards,
John D.
 
R

Richard Bos

ImpalerCore said:
If I read you correctly, it sounds like nowadays assert is the wrong
level of abstraction for checking against dereferenced NULL pointers,
due to operating system maturity.

No; it's more that a library function is the wrong level of abstraction
to use assert() at, unless you're developing and testing that same
library. assert() is good when its output is seen by developers who can
do something about the error. When it's seen (or more likely, not even
seen) by ordinary users, it's useless.
I was under the impression that assert was for developers, not
computer users. My understanding is that assert is NDEBUGed out
before it gets to the computer user.

The problem is that you don't #include the library. You #include only
the prototypes (plus related material) for the library functions. In
almost all cases, you link in the actual code, already compiled.
Therefore, if you, the user-programmer, #define NDEBUG, that has no
effect at all on the already compiled library functions. A library that
has been compiled with assert()s in place will always have those
assert()s in place, no matter what the program it is linked with does.

Of course, if, as a developer, you would want strcpy() to trigger an
assert() to catch stray null pointers in your own code, a Standard
library with assert() in it can be a useful thing. But your
understanding above is correct: you would want your release build to use
the normal, non-assert() library.

Richard
 
R

Richard Bos

bart.c said:
He doesn't need to. It can just be part of the report the user sends to the
developer.

Hah! I want your users. Mine only give me useful reports if I put up a
window containing exact instructions in very un-technical words. If I
print a (to them) cryptic line of techledygook on a console they might
not even have, let alone ever look at, I get sweet Fanny Adams.

Richard
 
R

Richard Bos

ImpalerCore said:
On May 12, 4:21=A0am, Nick Keighley <[email protected]>

If the C standard library doesn't populate their library with asserts,
why should I populate my library with asserts at all?

You should put them in _while you're still developing it_. Once you
start using it - even more so once someone else starts using it - you
compile a NDEBUGged version.
I would not be surprised if someone's version of the Standard library
did exactly that. Of course, unless you have its source code, you'll
never see the difference.
And the disagreement leaves me with the impression that the assert
mechanism wasn't designed properly in the first place since no one can
seem to agree on what exactly it or NDEBUG is intended for.

It might be more balanced to say that, back in the days before the first
Standard, when assert() was designed, the average UNIX user was a lot
closer to being a programmer - and if not, to knowing one personally.

Richard
 

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,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top