A C Adventure: your comments are welcome

N

Nick Keighley

As you are a proponant of OO I'm surprised at this. Wouldn't
it be better to decide what the strings are going to be used
for, then propose operations (methods) on those strings, and
only then decide tentativly on a representation. If you encapsulate
properly then you can change the representaion (data structure)
with no impact on the application code. You are too keen to
expose your representation.
[...] In this thread I shall re-learn C, [by
implenting a string library]

<snip>

I haven't examined your code in detail but just a couple of points.

1. write a test harness! It makes life so much easier if you test as
you go.
struct TYPstringNode * mkStringNode

I don't particularly like the style
Type * t

I use
Type *t

in C, as do most other people
                       (char * ptrNodeCharacters,
                        unsigned int uintStartIndex,
                        unsigned int uintLength,
                        struct TYPstringNode * ptrParent,
                        struct TYPstringNode * ptrLeft,
                        struct TYPstringNode * ptrRight)
{
    struct TYPstringNode * ptrNewNode;
    if ((ptrNewNode =
         (struct TYPstringNode *)
         (malloc(sizeof(struct TYPstringNode))))
        ==
        NULL)

you've cast the return value of malloc(). This is unnecessary.

    {
        abort();
    }
    (*ptrNewNode).ptrNodeCharacters = ptrNodeCharacters;

there is an abbreviation in C. This can be written

ptrNewNode->ptrNodeCharacters = ptrNodeCharacters;

    struct TYPstringNode * ptrStringNode =
                    (uintSegments > 1
                     ?
                     ptrSourceChars + SEGMENT_MAX_LENGTH
                     :
                     ptrSourceChars,
                     uintStartIndex
                     +
                     (uintSegments > 1 ? SEGMENT_MAX_LENGTH : 0), //
80
                     uintSegments > 1
                     ?
                     min(uintLength - SEGMENT_MAX_LENGTH, uintLength)
                     :
                     uintLength,
                     ptrParent,
                     uintSegments > 1
                     ?
                     (ptrLeft = mkStringNode
                                (ptrSourceChars,
                                 uintStartIndex,
                                 SEGMENT_MAX_LENGTH,
                                 NULL, NULL, NULL))
                     :
                     NULL,
                     uintSegments > 2
                     ?
                     (ptrRight = mkString
                                 (NULL,
                                  ptrSourceChars
                                  +
                                  uintDoubleSegmentLength,
                                  uintStartIndex
                                  +
                                  uintDoubleSegmentLength,
                                  uintLength
                                  -
                                  uintDoubleSegmentLength))
                     :
                     NULL);

that looks horrendous. It must be easier to break it down.

int main()

int main (void)
is better style

<snip>
 
S

spinoza1111

It seems inappropriate to comment on the code in details since it has
obviously not had the benefit of a single test run, so I'll just say
that the ?: part also has comma operators in it that turn into
something else altogether.

<snip>

There was a missing function call, but this does raise an issue: how
does C syntax handle the fact that the comma is an operator? Doesn't
this mean that the comma operator may not appear in function calls
unless the expression of which it is the major operator is in its own
set of parentheses?

By the way:


ROPE findRopeAncestor(ROPE ptrRopeNode)
{
while((*ptrRopeNode).ptrParent != NULL)
ptrRopeNode = (*ptrRopeNode).ptrParent;
}


It seems now natural to use value parameters as work areas, so I take
back what I said about Dennis Ritchie's code.
 
A

Alan Curry

Would someone else please confirm that I'm telling the truth about a
newline in the OP's so-called "single-line comment"? Message ID is:
<[email protected]>

Let's do it with C! just to have some less-awful code in this awful thread.

I'm claiming 3 usual-pedantry exemptions. Feel free to attack the rest.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Pedantry-preemptive note #1:
Not interested in hearing that sockets aren't part of C. Would someone
miss the point that badly if I didn't say so? Several people I bet. */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

/* NNTP commands and replies are ASCII. If the local charset is different,
there needs to be some translation before the sends and after the
receives. */
#if 'A' != 65 || 'a' != 97 || '0' != 48
# error "Non-ASCII, huh? You've got some porting work to do."
#endif

#define NNTP_SERVER "nntp.aioe.org"
#define NNTP_PORT 119

#define GET_ARTICLE "article " \
"<[email protected]>\r\n"

#define ARTICLE_TERMINATOR "\r\n.\r\n"

int main(void)
{
int fd;
FILE *fp;
struct hostent *hp;
struct sockaddr_in sa;
int c;
char *article, *p;
size_t article_len;
size_t article_allocsz;
int found;

fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd < 0) {
perror("socket");
return EXIT_FAILURE;
}

hp = gethostbyname(NNTP_SERVER);
assert(hp->h_addrtype==AF_INET);

memset(&sa, 0, sizeof sa);
sa.sin_family = AF_INET;
sa.sin_port = htons(NNTP_PORT);
sa.sin_addr=*(struct in_addr *)hp->h_addr;

if(connect(fd, (struct sockaddr *)&sa, sizeof sa)) {
perror("connect to " NNTP_SERVER);
return EXIT_FAILURE;
}

fp = fdopen(fd, "r+");
if(!fp) {
perror("fdopen");
return EXIT_FAILURE;
}

/* NNTP server should send a greeting line starting with "200" */
if(getc(fp) != '2' ||
getc(fp) != '0' ||
getc(fp) != '0') {
fprintf(stderr, "Bad greeting from NNTP server\n");
return EXIT_FAILURE;
}
while((c=getc(fp))!=EOF && c!='\n') {
/* nothing, just discarding rest of line */;
}

/* Send the command to get the article */
if(fwrite(GET_ARTICLE, 1, sizeof(GET_ARTICLE)-1, fp) !=
sizeof(GET_ARTICLE)-1) {
/* Pedantry-preemptive note #2:
Not interested in hearing that stdio functions can fail without
setting errno. We have sockets, we have sanity. */
perror("fwrite");
return EXIT_FAILURE;
}
if(fflush(fp)) {
perror("fflush");
return EXIT_FAILURE;
}

/* NNTP server should send a 220 status line before the article text */
if(getc(fp) != '2' ||
getc(fp) != '2' ||
getc(fp) != '0') {
fprintf(stderr, "Bad reply from NNTP server\n");
return EXIT_FAILURE;
}
while((c=getc(fp))!=EOF && c!='\n') {
/* nothing, just discarding rest of line */;
}

/* Read loop: slurp the whole article into memory. */
article = 0;
article_len = article_allocsz = 0;
while(1) {
/* If the buffer is full, grow it. */
if(article_len == article_allocsz) {
size_t newsize = (article_allocsz+1024)*4;
/* size_t overflow in the size of a usenet article? */
if(newsize <= article_allocsz) {
fprintf(stderr, "Redonkulous!\n");
return EXIT_FAILURE;
}

article_allocsz = newsize;
/* Pedantry-preemptive note #3:
Not interested in hearing how the DS9K doesn't reclaim malloced
memory when a process exits. */
article = realloc(article, article_allocsz);
if(!article) {
perror("realloc");
return EXIT_FAILURE;
}
}

/* Get and append characters one at a time so we don't try to keep
reading after the ARTICLE_TERMINATOR, because the NNTP server will
be waiting for another command at that point. */
c = getc(fp);
if(c==EOF) {
if(ferror(fp)) {
perror("read from socket");
return EXIT_FAILURE;
}
if(feof(fp)) {
fprintf(stderr, "Got premature EOF from NNTP server\n");
return EXIT_FAILURE;
}
}
article[article_len++] = c;
if(article_len >= 5 &&
!memcmp(article+article_len-5, ARTICLE_TERMINATOR, 5))
break;
}

article_len -= 3; /* The last ".\r\n" is not part of the article. */

/* Now we've got the full article text exactly as the news server sent
it. It's not \0-terminated. Be paranoid and assume it might contain
some internal \0's, so use mem*() functions instead of strstr() */
found = 0;
for(p=memchr(article, '/', article_len)
; p ;
p=memchr(p+1, '/', article+article_len-(p+1))) {
if(!memcmp(p, "//\r\n80", 6)) {
printf("Found //\\r\\n80 at byte offset %ld\n", (long)(p-article));
++found;
}
}

if(!found)
return EXIT_FAILURE; /* failed to find the string */

return EXIT_SUCCESS; /* exit success. Googlegrouper failure. */
}

Results:

Found //\r\n80 at byte offset 11742
 
B

bartc

Richard Heathfield said:
spinoza1111 said:


Would someone else please confirm that I'm telling the truth about a
newline in the OP's so-called "single-line comment"? Message ID is:
<[email protected]>



No, I'm claiming that you posted 80 as a C statement. In other words,
it appeared in code for which you invited comments.

This happens all the time with C code posted here. Usually the snippets are
small, and the obvious compilation errors it causes can be fixed without
even thinking about it.

(I think it can happen with *any* language that has comments that finish at
end-of-line, where code is posted to usenet (and some line-oriented
languages would have the problem even without comments). For example, Ada,
Basic, Python, Fortran you may possibly have heard of.)

It's really, really not a big deal. That fact that you have a jobsworth of a
compiler that refuses to recognise such a widely used comment style and
possibly doesn't have a simple option to enable them, is your problem.
 
B

Beej Jorgensen

Richard Heathfield said:
Would someone else please confirm that I'm telling the truth about a
newline in the OP's so-called "single-line comment"? Message ID is:
<[email protected]>

It does contain a newline.

But since it's so obviously the result of errant wrapping, it doesn't
seem to be worth even bringing up.

-Beej
 
S

spinoza1111

spinoza1111said:







No, it was in the code you sent out from your newsreader. I've checked
the article source. Check it yourself, if you know how. Message ID:


I often confuse actual newlines with actual newlines. It's a weakness
of mine.


It's your oversight, not mine. This is independently and objectively
verifiable by an inspection of the article source, and this
inspection can be conducted by anyone with the wit to work out how to
use a message-ID. This would appear to exclude you (although I'd be
happy to be proved wrong about that, at least), but lots of other
people are able to check it.

If you post broken code, the claim "it wasn't broken when I pasted it
into my newsreader", whilst perhaps appearing cute to some people, is
far from convincing - not least to the implementation. Compilers
don't bother reading your sociology claptrap excuses - they can
simply say "syntax error" and be done with you.

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
This line unintentionally left unblank- Hide quoted text -

- Show quoted text -

You're both dumb and evil. The newline is added by formatting. A
competent programmer would have known that, since he'd see that the 80
has no meaning. Since I was using the Notepad to edit the program and
getting line numbers from Navia's program, I wanted to keep track
where I was. The code wouldn't have compiled with a real newline, and
this you should have known.

You're dumb because you failed to notice the real error in the
code...which did not prevent the code from compiling. The code omitted
a call on mkStringNode right after the first equals sign although it
compiled correctly, since the parenthesized argument stack is itself a
valid assignable expressions with commas as its lowest precedence
operators. This was a typo which has long since been fixed, and it's
due to the primitive state of syntax analysis at the time C was
invented.

You're evil because you're using your own stupidity and lack of
diligence to imply that typographical errors are equivalent to
substantive bugs.

Here is the current statement in the current code, which will be
posted when it works or seems to work, for comments. Your comments are
not very welcome but shall be answered. I don't know if it will
compile. ROPE has been #defined to struct ptrRopeNode *, and I have,
following a remark of Julienne's, change "string" to "rope".

If you were competent, I would not have to explain this statement. It
hasn't been tested, yet, but it makes a rope node with at most a left
and right child node. The left child points to a rope node but the
right child points to a complete subrope, and the statement builds a
rope by calling the procedure recursively. Don't bother pointing out
that the tree is unbalanced: I've explained why this is probably not a
problem.

Richard, competent maintenance programmers, of the sort who clean up
the messes made by people like you, can see where formatters have
added newlines and where a function name is missing, and they do so
without impugning the professsionalism of others. This is because the
best of them know that a program, as in Donald Knuth's definition, is
a communication between humans about the behavior of computers, and
that in human communication, you need some elementary decency...to
avoid making a toxic data smog of charge and countercharge.

Why don't you just go away until you understand this? And how on EARTH
did you ever keep a programming job, when you spend so much time
trying to destroy people?

My President has buckled under negative campaigns and lies about
"death panels", but YOU can go **** yourself.

Here is the code.

ROPE ptrStringNode =
mkRopeNode
(// ----- Pointer to source chars ----------------------------
(uintSegments > 1
?
ptrSourceChars + SEGMENT_MAX_LENGTH
:
ptrSourceChars),
// ----- Parent segment start index
-------------------------
(lngStartIndex
+
(uintSegments > 1
?
SEGMENT_MAX_LENGTH
:
0)),
// ----- Parent segment length (screw you Heathfield)
-------
(uintSegments > 1
?
MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength)
:
uintSegmentLength),
// ----- Parent's own parent or null
------------------------
ptrParent,
// ----- Left child node exists when segments > 1
-----------
(uintSegments > 1
?
(ptrLeft = mkRopeNode
(ptrSourceChars,
lngStartIndex,
SEGMENT_MAX_LENGTH,
NULL, NULL, NULL))
:
NULL),
// ----- Right child node exists when segments > 1
----------
(uintSegments > 2
?
(ptrRight = mkString
(NULL,
ptrSourceChars
+
uintDoubleSegmentLength,
lngStartIndex
+
uintDoubleSegmentLength,
uintSegmentLength
-
uintDoubleSegmentLength))
:
NULL));

I haven't had the time to see if the revised statement compiles since
I am adding comments and improvements to the rest of the code, but the
above is meant, in the spirit of Knuth's definition, to communicate my
intention to human beings, as well as Heathfield. Don't waste my time
as does Heathfield and I won't waste yours.

Ben B: the code with the missing function name seemed to be an
expression whose lowest precedence operators were the comma. I like
the comma op but did not mean to use it. Isn't there a syntax issue in
a function call of the form

a(p1, p2 ... pn)?

That is, doesn't the PARSER have to know the number of arguments to
avoid treating the parameter list as one expression?
 
S

spinoza1111

Can you please re-insert a "your really know bugger-all about C" line?
There's if you're going to feed him, at least feed him some bile.

// Not compiled nor tested, posted for CONSTRUCTIVE criticism
//
#define ROPE struct ptrStringNode *
#define HEATHFIELD NULL
ROPE ptrStringNode =
mkRopeNode
(// ----- Pointer to source chars ----------------------------
(uintSegments > 1
?
ptrSourceChars + SEGMENT_MAX_LENGTH
:
ptrSourceChars),
// ----- Parent segment start index
-------------------------
(lngStartIndex
+
(uintSegments > 1
?
SEGMENT_MAX_LENGTH
:
0)),
// ----- Parent segment length (screw you Heathfield)
-------
(uintSegments > 1
?
MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength)
:
uintSegmentLength),
// ----- Parent's own parent or null
------------------------
ptrParent,
// ----- Left child node exists when segments > 1
-----------
(uintSegments > 1
?
(ptrLeft = mkRopeNode
(ptrSourceChars,
lngStartIndex,
SEGMENT_MAX_LENGTH,
NULL, NULL, NULL)) // HEATHFIELD, HEATHFIELD,
HEATHFIELD OMIGOD A LINE BREAK SHOULD OCCUR HERE
:
NULL),
// ----- Right child node exists when segments > 1
----------
(uintSegments > 2
?
(ptrRight = mkString
(NULL,
ptrSourceChars
+
uintDoubleSegmentLength,
lngStartIndex
+
uintDoubleSegmentLength,
uintSegmentLength
-
uintDoubleSegmentLength))
:
NULL));
 
S

spinoza1111

    // Not compiled nor tested, posted for CONSTRUCTIVE criticism
    //
    #define ROPE struct ptrStringNode *
    #define HEATHFIELD NULL
    ROPE ptrStringNode =
         mkRopeNode
        (// ----- Pointer to source chars ----------------------------
         (uintSegments > 1
           ?
           ptrSourceChars + SEGMENT_MAX_LENGTH
           :
           ptrSourceChars),
          // ----- Parent segment start index
-------------------------
          (lngStartIndex
          +
           (uintSegments > 1
           ?
            SEGMENT_MAX_LENGTH
           :
           0)),
          // ----- Parent segment length (screw you Heathfield)
-------
          (uintSegments > 1
           ?
           MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength)
           :
           uintSegmentLength),
          // ----- Parent's own parent or null
------------------------
          ptrParent,
          // ----- Left child node exists when segments > 1
-----------
          (uintSegments > 1
           ?
           (ptrLeft = mkRopeNode
                      (ptrSourceChars,
                       lngStartIndex,
                       SEGMENT_MAX_LENGTH,
                       NULL, NULL, NULL)) // HEATHFIELD, HEATHFIELD,
HEATHFIELD OMIGOD A LINE BREAK SHOULD OCCUR HERE
           :
           NULL),
           // ----- Right child node exists when segments > 1
----------
           (uintSegments > 2
            ?
            (ptrRight = mkString
                        (NULL,
                         ptrSourceChars
                         +
                         uintDoubleSegmentLength,
                         lngStartIndex
                         +
                         uintDoubleSegmentLength,
                         uintSegmentLength
                         -
                         uintDoubleSegmentLength))
             :
             NULL));







- Show quoted text -- Hide quoted text -

- Show quoted text -

OK, I see the problem. I like code "fences" to divide things up but
I'll change the style for posting here in all future code. Heathfield
is still to blame for making a mountain out of a molehill.
 
B

Ben Bacarisse

spinoza1111 said:
Ben B: the code with the missing function name seemed to be an
expression whose lowest precedence operators were the comma. I like
the comma op but did not mean to use it. Isn't there a syntax issue in
a function call of the form

a(p1, p2 ... pn)?

That is, doesn't the PARSER have to know the number of arguments to
avoid treating the parameter list as one expression?

I suppose that would be one way, but I don't know any language that
uses that method. The syntax of C tells you that a(p1, p2, p3) has no
comma operators in it.
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:


Getting it to a state where others can compile it will be the first
hurdle for the OP.

That's a rather artificial distinction to me. When I want to review
some posted code, I feed it to the compiler and step though the errors
and warnings. It's quite common to find some of the errors are due
to wrapped line-oriented comments and I fix those as I go if it seems
obvious what has happened.

Of course, this is risky -- I am guessing at the poster's intent --
but this is often one of easiest things to guess correctly.
 
N

Nick Keighley

Here is the current statement in the current code, which will be
posted when it works or seems to work, for comments. Your comments are
not very welcome but shall be answered. I don't know if it will
compile.

then compile it.
ROPE has been #defined to struct ptrRopeNode *,

not a good idea. The preprocessor doesn't really understand C
and this can lead to problems. Much better to define type aliases
using the typedef keyword that C provides for this purpose.
I'd suggest

typedef struct ptrRopeNode * ROPE;

except it's usually a bad idea to hide pointers in typedefs
and if it's a typedef I wouldn't use UC. Hence

typedef struct ptrRopeNode Rope;

and I'd probably use another typedef to hide the struct (about
half of clc will disagree though)
and I have,
following a remark of Julienne's, change "string" to "rope".

and I still think the abstraction may be poor. Does your application
(you must have something in mind) need to distinguish strings from
ropes? Is this a generic string class or does the application
deal with "ropes" (which I guess are huge easy to edit strings).
Text editor application?
[...] It hasn't been tested,

I'd strongly suggest compiling *and* testing before posting.
If you write the tests at the same time as the code it is quite
painless
(cf. TDD- Though Don't Drink - the Kool Aid)

Here is the code.

    ROPE ptrStringNode =

with my suggested typedef this would be
Rope *ptrStringNode =

though better would be
Rope *rope =

or (I don't like this but it matches the style of the rest of the
program).
Rope *ptrRope =
         mkRopeNode
        (// ----- Pointer to source chars ----------------------------
         (uintSegments > 1
           ?
           ptrSourceChars + SEGMENT_MAX_LENGTH
           :
           ptrSourceChars),
          // ----- Parent segment start index
-------------------------
          (lngStartIndex
          +
           (uintSegments > 1
           ?
            SEGMENT_MAX_LENGTH
           :
           0)),
          // ----- Parent segment length (screw you Heathfield)
-------
          (uintSegments > 1
           ?
           MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength)
           :
           uintSegmentLength),
          // ----- Parent's own parent or null
------------------------
          ptrParent,
          // ----- Left child node exists when segments > 1
-----------
          (uintSegments > 1
           ?
           (ptrLeft = mkRopeNode
                      (ptrSourceChars,
                       lngStartIndex,
                       SEGMENT_MAX_LENGTH,
                       NULL, NULL, NULL))
           :
           NULL),
           // ----- Right child node exists when segments > 1
----------
           (uintSegments > 2
            ?
            (ptrRight = mkString
                        (NULL,
                         ptrSourceChars
                         +
                         uintDoubleSegmentLength,
                         lngStartIndex
                         +
                         uintDoubleSegmentLength,
                         uintSegmentLength
                         -
                         uintDoubleSegmentLength))
             :
             NULL));

adding comments to a mess doesn't make it less of a mess.
Break it down into separate statements. Heavy commenting
is often a sign of poor modularisation (not something to tell
people or they stop writing the comments...).

/* perhaps like this */

if (uintSegments <= 1)
Rope *rope = mkRopeNode
(ptrSourceChars,
lngStartIndex,
uintSegmentLength,
ptrParent, NULL, NULL);
else
if (uintSegments < 2)
Rope *rope = mkRopeNode
(ptrSourceChars + SEGMENT_MAX_LENGTH,
lngStartIndex + SEGMENT_MAX_LENGTH,
MIN (uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength),
ptrParent,
ptrLeft =
mkRopeNode
(ptrSourceChars, lngStartIndex,
SEGMENT_MAX_LENGTH, NULL, NULL, NULL),
NULL);
else
Rope *rope = mkRopeNode
(ptrSourceChars + SEGMENT_MAX_LENGTH,
lngStartIndex + SEGMENT_MAX_LENGTH,
MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength),
ptrParent,
ptrLeft =
mkRopeNode (ptrSourceChars, lngStartIndex,
SEGMENT_MAX_LENGTH, NULL,
NULL, NULL),
ptrRight =
mkString
(NULL,
ptrSourceChars +
uintDoubleSegmentLength,
lngStartIndex +
uintDoubleSegmentLength,
uintSegmentLength -
uintDoubleSegmentLength));

[I may have introduced bugs but it illustrates the idea]
It's still messy but it tries to break things into steps.
I'd use yet more temporary variables. I don't like that ptrRight
ptrLeft assignment in the function call. They seem candidates to be
assigned to outside the function call.

I haven't had the time to see if the revised statement compiles since
I am adding comments and improvements to the rest of the code, but the
above is meant, in the spirit of Knuth's definition, to communicate my
intention to human beings [...]

which, I submit, you failed to do.

<snip>
 
S

spinoza1111

then compile it.

I am working on this during the commute, and I prefer to polish the
code to some degree before mindlessly compiling it. I am sharing this
code with the group while it is being developed to let you clowns
participate, not for you to make unfounded judgements on competence.

Kernighan counts it as a virtue that Dennis Ritchie completed the so-
called "regular expression" processor in Beautiful Code in an hour,
and this attitude results in a culture of undocumented slapdash, or
programmers who have no life. Life is short, art is long.

The current code will be posted at the bottom of this reply.
not a good idea. The preprocessor doesn't really understand C
and this can lead to problems. Much better to define type aliases
using the typedef keyword that C provides for this purpose.
I'd suggest

  typedef struct ptrRopeNode * ROPE;

except it's usually a bad idea to hide pointers in typedefs
and if it's a typedef I wouldn't use UC. Hence

  typedef struct ptrRopeNode Rope;

and I'd probably use another typedef to hide the struct (about
half of clc will disagree though)

This suggestion makes sense, because I agree that the preprocessor
fucks things up. I will revise the next edition to use typedefs as you
suggest. This is why I am sharing this code with this group: to
improve the toxic atmosphere of this group by letting people make
suggestions without impugning their professional credentials (unless
their combined stupidity and malice exceeds an upper bound).
and I still think the abstraction may be poor. Does your application

Don't know if the abstraction can be much better while staying in C
(and that's my point).
(you must have something in mind) need to distinguish strings from
ropes? Is this a generic string class or does the application
deal with "ropes" (which I guess are huge easy to edit strings).
Text editor application?
[...] It hasn't been tested,

I'd strongly suggest compiling *and* testing before posting.
If you write the tests at the same time as the code it is quite
painless
(cf. TDD- Though Don't Drink - the Kool Aid)

As I note above, as a full time Hong Kong teacher who works a six day
week, I work on this during the commute. As I note above, this is a
participatory project for this group.

I am past caring about a "professional reputation", since I don't
choose to work as a programmer for money any more, and the normalized
deviance of this group, and of programming groups in meat space, is
the reason.
with my suggested typedef this would be
      Rope *ptrStringNode =

though better would be
      Rope *rope =

Very nice.
or (I don't like this but it matches the style of the rest of the
program).
      Rope *ptrRope =






adding comments to a mess doesn't make it less of a mess.
Break it down into separate statements. Heavy commenting
is often a sign of poor modularisation (not something to tell
people or they stop writing the comments...).

I need to show the parameters of the call. I agree that heavy
commenting by people who can't write sucks. I can write.
   /* perhaps like this */

    if (uintSegments <= 1)
        Rope *rope = mkRopeNode
                        (ptrSourceChars,
                         lngStartIndex,
                         uintSegmentLength,
                         ptrParent, NULL, NULL);
    else
    if (uintSegments < 2)
        Rope *rope = mkRopeNode
                       (ptrSourceChars + SEGMENT_MAX_LENGTH,
                        lngStartIndex + SEGMENT_MAX_LENGTH,
                        MIN (uintSegmentLength - SEGMENT_MAX_LENGTH,
                             uintSegmentLength),
                        ptrParent,
                        ptrLeft =
                            mkRopeNode
                              (ptrSourceChars, lngStartIndex,
                               SEGMENT_MAX_LENGTH, NULL, NULL, NULL),
                       NULL);
    else
        Rope *rope = mkRopeNode
                       (ptrSourceChars + SEGMENT_MAX_LENGTH,
                        lngStartIndex + SEGMENT_MAX_LENGTH,
                        MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
                            uintSegmentLength),
                        ptrParent,
                        ptrLeft =
                            mkRopeNode (ptrSourceChars, lngStartIndex,
                                        SEGMENT_MAX_LENGTH, NULL,
NULL, NULL),
                        ptrRight =
                          mkString
                             (NULL,
                              ptrSourceChars +
uintDoubleSegmentLength,
                              lngStartIndex +
uintDoubleSegmentLength,
                              uintSegmentLength -
uintDoubleSegmentLength));

[I may have introduced bugs but it illustrates the idea]

Yes, and unlike Richard Heathfield, I won't use the bugs to impugn
your professional reputation.
It's still messy but it tries to break things into steps.
I'd use yet more temporary variables. I don't like that ptrRight
ptrLeft assignment in the function call. They seem candidates to be
assigned to outside the function call.

OK, I prefer expressions to statements. I should have learned Lisp
more thoroughly and stayed with it.

I haven't had the time to see if the revised statement compiles since
I am adding comments and improvements to the rest of the code, but the
above is meant, in the spirit of Knuth's definition, to communicate my
intention to human beings [...]

which, I submit, you failed to do.

That's not true. You've been able to make useful suggestions and
rewrite the Godzilla statement in your preferred way.

Anyway, here is the code right now. It hasn't been compiled and it
hasn't been tested. It needs a routine to determineStringLength()
which will use recursion and which will be quite simple to write (add
the length of the left segment to the length passed, zero at the top
level of recursion, and call yourself for the right hand side).

But to make such a routine elegant, it turns out that each node needs
to have the length of all nodes below it, so this entails the revision
of other code.

// ***************************************************************
// * *
// * Rope implementation *
// * *
// * This program implements strings, called ropes, which can *
// * contain any character and can be of any length.
*
// * *
// * This code is best viewed using a monospace font such as *
// * Courier New, in a line length of 67 characters. *
// * *
// * The rest of this header addresses these topics: *
// * *
// * *
// * * The "rope" as represented in this code *
// * * Configuring this code for testing *
// * *
// * *
// * THE "ROPE" AS REPRESENTED IN THIS CODE -------------------- *
// * *
// * The rope is defined as the binary tree of its nodes, where *
// * each node points to up to SEGMENT_MAX_LENGTH characters of *
// * the string. Each node of the binary tree contains: *
// * *
// * *
// * * A pointer to the start of the segment *
// * *
// * * The node type: *
// * *
// * + ENUnodeType.child indicates that the node is a *
// * child node of another node.
*
// * *
// * + ENUnodeType.ancestorLengthKnown indicates that the*
// * node has no parent AND that the length of the *
// * entire string is at this time, known. *
// * *
// * + ENUnodeType.ancestorLengthTooLarge indicates that *
// * the node has no parent AND that the length of the *
// * entire string exceeds a maximum value. *
// * *
// * By default, this maximum value is 2^63-1, the *
// * maximum length of an unsigned "long long" less a *
// * margin to allow for testing the length. The *
// * maximum value, however, can be set to smaller *
// * values for testing. *
// * *
// * + ENUnodeType.ancestorLengthUnknown indicates that *
// * the node has no parent AND that the length of the *
// * entire string is at this time, fully unknown. *
// * *
// * * The 64 bit unsigned string length. Note that this *
// * value may be unusable: *
// * *
// * + The length may be undetermined: here the node *
// * type will be ENUnodeType.ancestorLengthUnknown *
// * *
// * + The length may exceed long-long precision: here *
// * the node type will be *
// * ENUnodeType.ancestorLengthUnknown *
// * *
// * + The node may be a child node: here the node type *
// * will be ENUnodeType.child *
// * *
// * * The start index of the rope segment (substring) *
// * within the full string; note that in rare cases this*
// * is unknown when the string is longer than 2^64-1 *
// * characters, and the segment is located on the right *
// * of the string, this value may also be unknown. Here *
// * it is set to -1 (UNKNOWNLENGTH). *
// * *
// * * The length of the rope segment (substring) *
// * *
// * * The address of the parent of the node or NULL *
// * *
// * * The address of the left child of the node (holding *
// * characters to the left of the segment) or NULL *
// * *
// * * The address of the right child of the node (holding *
// * characters to the right of the segment) or NULL *
// * *
// * *
// * CONFIGURING THIS CODE FOR TESTING ------------------------- *
// * *
// * The following symbols may be set to configure a test of this*
// * code. *
// * *
// * *
// * * SEGMENT_MAX_LENGTH: maximum length of a rope string *
// * segment *
// * *
// * * STRING_MAX_RECORDABLE_LENGTH: maximum recordable *
// * length of a string, beyond which the string length *
// * is officially "unknown". To test whether strings *
// * whose lengths are not known, this symbol may be set *
// * to a small value *
// * *
// * * TEST_STRING_LENGTH: length of the string used to *
// * test this code *
// * *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges Started version 1 *
// * *
// * *
// * I S S U E S ----------------------------------------------- *
// * DATE POSTER DESCRIPTION AND RESOLUTION *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges To be implemented: use extra *
// * precision arithmetic for unbounded*
// * strings *
// * *
// * *
// ***************************************************************

// ***** Standard includes ***************************************

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <stddef.h>

// ***** Configuration *******************************************

#define SEGMENT_MAX_LENGTH 32
#define STRING_MAX_RECORDABLE_LENGTH 1024 // Set to 2^63-1 for
// actual use
#define TEST_STRING_LENGTH 2000

// ***** Macros **************************************************

// --- Statement macro to handle errors
#define ERRORHANDLER(strMessage) \
{ \
printf("%s\n", (strMessage)); abort(); \
}

// --- Expression macro to perform malloc
#define MALLOC_(bytesNeeded, cast) \
( (cast)(malloc((bytesNeeded))) )

// --- Statement macro to perform malloc with error checking
#define MALLOC(ptr, bytesNeeded, cast, purpose)
{ \
if (((ptr) = MALLOC_((bytesNeeded),(cast))) == NULL)) \
{ \
printf \
("Can't get storage: purpose was: %s\n", (purpose)); \
errorHandler("Malloc failed"); \
} \
}

// --- Symbols
#define KNOWNLENGTH 0
#define UNKNOWNLENGTH -1
#define ABSURDLENGTH -2

// ***** Rope definition *****************************************

#define ROPE struct TYPropeNode *

enum ENUnodeType
{
child,
ancestorLengthKnown,
ancestorLengthTooLarge,
ancestorLengthUnknown
};

struct TYPropeNode
{
enum ENUnodeType enuNodeType;
char * ptrNodeCharacters;
unsigned long long ulngStringLength;
unsigned long long ulngSegmentStartIndex;
unsigned int uintSegmentLength;
ROPE ptrParent;
ROPE ptrLeft;
ROPE ptrRight;
};

// ***** Procedures **********************************************

// ---------------------------------------------------------------
// Create a rope node
//
// To create the Ancestor node, pass a non-null ptrParent and a
// lngStringLength:
//
// * 0 or positive indicates a known length
//
// * -1 (UNKNOWNLENGTH) indicates a fully unknown length
//
// * -2 (ABSURDLENGTH) indicates an unknown length greater
// than the maximum recordable length
//
//
ROPE mkRopeNode
(char * ptrNodeCharacters,
long long lngStringLength
long long lngSegmentStartIndex,
unsigned int uintSegmentLength,
ROPE ptrParent,
ROPE ptrLeft,
ROPE ptrRight)
{
ROPE ptrNewNode;
MALLOC(ptrNewNode, sizeof(ROPE), ROPE, "Get a rope node")
(*ptrNewNode).ptrNodeCharacters = ptrNodeCharacters;
if (ptrParent == NULL)
{
if (lngStringLength >= 0)
{
(*ptrNewNode).enuNodeType =
ENUnodeType.ancestorLengthKnown;
} else
{
if (lngStringLength == UNKNOWNLENGTH)
{
(*ptrNewNode).enuNodeType =
ENUnodeType.ancestorLengthUnknown;
} else
{
if (lngStringLength == ABSURDLENGTH)
{
(*ptrNewNode).enuNodeType =
ENUnodeType.ancestorLengthTooLarge;
} else
{
errorHandler("Invalid string length");
}
}
}
} else
{
(*ptrNewNode).enuNodeType = ENUnodeType.child;
}
(*ptrNewNode).ulngStringLength = lngStringLength;
(*ptrNewNode).lngSegmentStartIndex = lngSegmentStartIndex;
(*ptrNewNode).uintSegmentLength = uintSegmentLength;
(*ptrNewNode).ptrParent = ptrParent;
(*ptrNewNode).ptrLeft = ptrLeft;
(*ptrNewNode).ptrRight = ptrRight;
return ptrNewNode;
}

// ---------------------------------------------------------------
// Make string
//
//
ROPE mkString
(ROPE ptrParent,
char * ptrSourceChars,
unsigned int lngStartIndex,
unsigned int uintSegmentLength)
{
unsigned int uintOffset;
ROPE ptrLeft = NULL;
ROPE ptrRight = NULL;
unsigned int uintSegments;
unsigned int uintDoubleSegmentLength;
if (uintSegmentLength <= SEGMENT_MAX_LENGTH)
uintSegments = 1;
else
{
if (uintSegmentLength
<=
(uintDoubleSegmentLength = SEGMENT_MAX_LENGTH << 1))
uintSegments = 2;
else
uintSegments = 3;
}
ROPE ptrStringNode =
mkRopeNode
(// ----- Pointer to source chars -----------------------
(uintSegments > 1
?
ptrSourceChars + SEGMENT_MAX_LENGTH
:
ptrSourceChars),
// ----- Parent segment start index --------------------
(lngStartIndex
+
(uintSegments > 1
?
SEGMENT_MAX_LENGTH
:
0)),
// ----- Parent segment length (screw you Heathfield) --
(uintSegments > 1
?
MIN(uintSegmentLength - SEGMENT_MAX_LENGTH,
uintSegmentLength)
:
uintSegmentLength),
// ----- Parent's own parent or null -------------------
ptrParent,
// ----- Left child node exists when segments > 1 ------
(uintSegments > 1
?
ptrLeft = mkRopeNode
(ptrSourceChars,
lngStartIndex,
SEGMENT_MAX_LENGTH,
NULL, NULL, NULL)
:
NULL),
// ----- Right child node exists when segments > 1 ----
(uintSegments > 2
?
(ptrRight = mkString
(NULL,
ptrSourceChars
+
uintDoubleSegmentLength,
lngStartIndex
+
uintDoubleSegmentLength,
uintSegmentLength
-
uintDoubleSegmentLength))
:
NULL);
if (ptrStringNode != NULL)
{
(*ptrStringNode).ptrLeft = ptrLeft;
(*ptrStringNode).ptrRight = ptrRight;
if (ptrLeft != NULL)
(*((*ptrStringNode).ptrLeft)).ptrParent =
ptrStringNode;
if (ptrRight != NULL)
(*((*ptrStringNode).ptrRight)).ptrParent =
ptrStringNode;
}
return ptrStringNode;
}

// ---------------------------------------------------------------
// Find rope segment's ancestor (top of rope tree)
//
//
ROPE findRopeAncestor(ROPE ptrRopeNode)
{
if (ptrToNode == NULL)
ERRORHANDLER
("Null parameter passed to findRopeAncestor()");
if ((*ptrRopeNode).enuNodeType != ENUnodeType.child)
return ptrRopeNode;
while((*ptrRopeNode).ptrParent != NULL)
ptrRopeNode = (*ptrRopeNode).ptrParent;
return ptrRopeNode;
}

// ---------------------------------------------------------------
// Determine rope length
//
//
void determineRopeLength(ROPE ptrToNode,
unsigned long long ulngLength)
{
// Will check for overflow (old length plus length of left
// segment out of bounds), then, if no overflow, will add
// the left segment length to the length of the right subtree
}

// ---------------------------------------------------------------
// Rope to string length
//
//
unsigned long long rope2StringLength
(ROPE ptrToNode, int * intPtrStatus)
{
if (ptrToNode == NULL)
ERRORHANDLER
("Null parameter passed to rope2StringLength()");
ptrToNode = findRopeAncestor(ptrToNode);
if ((*ptrToNode).enuNodeType
==
ENUnodeType.ancestorLengthUnknown)
determineRopeLength(ptrToNode);
if ((*ptrToNode).enuNodeType
==
ENUnodeType.ancestorLengthKnown)
{
(*intPtrStatus) = KNOWNLENGTH;
return (*ptrToNode).ulngStringLength;
}
if ((*ptrToNode).enuNodeType
==
ENUnodeType.ancestorLengthUnknown)
{
(*intPtrStatus) = UNKNOWNLENGTH;
return 0;
} else
{
if ((*ptrToNode).enuNodeType
==
ENUnodeType.ancestorLengthTooLarge)
{
(*intPtrStatus) = UNKNOWNLENGTH;
return 0;
} else
{
ERRORHANDLER("Invalid node type found")
}
}
}

char* rope2String(ROPE ptrToNode)
{
char * ptrStringCopy =
(char *)malloc(rope2StringLength(ptrToNode));
if (ptrStringCopy == NULL) return NULL;
}

int main()
{
printf("Unlimited strings in basic C");
// ***** Insert test code *****
return 0;
}
 
S

spinoza1111

spinoza1111said:



This happens all the time with C code posted here. Usually the snippets are
small, and the obvious compilation errors it causes can be fixed without
even thinking about it.

(I think it can happen with *any* language that has comments that finish at
end-of-line, where code is posted to usenet (and some line-oriented
languages would have the problem even without comments). For example, Ada,
Basic, Python, Fortran you may possibly have heard of.)

It's really, really not a big deal. That fact that you have a jobsworth of a
compiler that refuses to recognise such a widely used comment style and
possibly doesn't have a simple option to enable them, is your problem.

The real problem is that no straight answer is available to the
question as to whether C, as human praxis and not some dead-on-arrival
standard, allows // style comments, and to many, many other questions
about C.
 
S

spinoza1111

spinoza1111said:



Yes, it does mean that. Comma as separator trumps comma as operator,

Which means that although having an operator do what the comma does is
a good idea, since it lets you code operations with side effects
clearly, the comma was a poor choice. The tilde would have been
better, but it may not have been available on Teletype keyboards in
1971.
so if you want this:

arg1 = a;
arg2 = b, c;
arg3 = d;

then either you can use temps explicitly as above, or you can do this:

func(a, (b, c), d);

but func(a, b, c, d) clearly isn't going to work.



Many people find that s->m is easier to read than (*s).m, which is why
that syntax was introduced.

Thanks for the heads-up, but I knew that. I wanted to stick to one
style.
Well, that's perhaps a beginning.

For the last time. These old developers are not gods. I met Kernighan,
and he's a nice guy, and I'd rather work with him than you, but don't
think for a second that I will ever "see the light".

I merely find it useful in a tree processor to treat the initial tree
pointer as a work area. The reason is that the meaning of the
identifier doesn't change.

The latest version of the code, with more documentation and work, is
at the bottom of this thread for your further comments. When you are
contributing your hard expertise in C, you are civil. I'd thank you to
continue being so.
 
S

spinoza1111

As you are a proponant of OO I'm surprised at this. Wouldn't
it be better to decide what the strings are going to be used
for, then propose operations (methods) on those strings, and
only then decide tentativly on a representation. If you encapsulate
properly then you can change the representaion (data structure)
with no impact on the application code. You are too keen to
expose your representation.

Interesting and perhaps valid point. Yes, I'm going bottom up. But C
provides no other way to represent strings.
[...] In this thread I shall re-learn C, [by
implenting a string library]

<snip>

I haven't examined your code in detail but just a couple of points.

1. write a test harness! It makes life so much easier if you test as
you go.

Coming soon
I don't particularly like the style
   Type * t

I use
   Type *t

in C, as do most other people

I like to make the operator-hood clearer
you've cast the return value of malloc(). This is unnecessary.

Are you sure in all cases of this? And is my cast a performance hit?
there is an abbreviation in C. This can be written

      ptrNewNode->ptrNodeCharacters = ptrNodeCharacters;

OK, you and Heathfield concur. I'll consider it.
<snip>






that looks horrendous. It must be easier to break it down.

No, it is easier to get it right. Coming soon.
 
S

spinoza1111

luserXtrog said:



So (after we include Phil - see his parallel reply), that's three
people who can attest to the existence of this supposedly
non-existent newline within a few short minutes of my posting the
above message ID.



No. If we are to trust his claim that lcc-win32 compiled the code he
wrote without producing any diagnostic messages, then the only
sensible conclusion is that the code he posted is not the code he
compiled. Any other conclusion would be a slur on lcc-win32.

What has happened here is very simple. The OP posted code without
ensuring that his newsreader would not "wrap" over-long lines.
Wrapping lines can break code in just about any language, but
single-line comments are especially susceptible to it, for the
obvious reason implied by their very name. So his newsreader /changed
the code/. This is hardly a new phenomenon to experienced programming
Usenauts - and what the rest of us do is say "oops, sorry, egg on
face and all that, yep, let me fix it...taptaptap... There! Try this
instead", and we re-post the code with shorter lines. What we *don't*
do is launch into denial and accusations of lying.

You've already changed your story. Other posters have asked you to
drop this issue. In fact, I keep lines at 72 characters in all my
code, since I started in the punched card era, and 72..80 were a
sequence number. You knew this but made a wild accusation. Yes, I
should have known that usenet would truncate and add newlines, but
that's not what you accused me of. You accused me of either continuing
a // comment or inserting 80 for no reason.

You're making a complete fool of yourself except when you use your
knowledge of C. Please behave yourself or leave this thread.
 
S

spinoza1111

That's how it looks from the midwest.



Could it be that lcc-win is allowing statements without a semicolon?

Don't you start on Jacques Navia: he's a better programmer than you'll
ever be.
It did (the most recent version, posted today, has not been compiled).
You acknowledge below that the newsreader adds the newline, changing
your story.
[snippity]
 
S

spinoza1111

Richard Heathfield said:
spinoza1111said:


As rendered by googlegroups itself:
"""
                     ptrSourceChars,
                     uintStartIndex
                     +
                     (uintSegments > 1 ? SEGMENT_MAX_LENGTH : 0), //
80
                     uintSegments > 1
                     ?
                     min(uintLength - SEGMENT_MAX_LENGTH, uintLength)
                     :
                     uintLength,
"""

Clear as the nose on your face.

Now please killfile the troll. You don't need to protect anyone from
his idiocy, as he's already demonstrated it so clearly.

No, you get out of here. You were misled by Heathfield, who knew that
the newsreader adds the newline (he's not stupid) but covered-up that
fact because he's evil, charging me with coding 80 with no semicolon.
 
S

spinoza1111

Ben Bacarisse said:



Yes, but that was a minor issue on which I merely commented rather
briefly. But I identified *other* diagnosable errors which, as far as
I know, have not been addressed.

You're lying. You tried to start Yet Another discussion of my
incompetence, and you went down...in flames. Now behave yourself. We
need your expertise in C.
 
B

Ben Bacarisse

spinoza1111 said:
// ***************************************************************
// * *
// * Rope implementation *
// * *
// * This program implements strings, called ropes, which can *
// * contain any character and can be of any length.
*
// * *
// * This code is best viewed using a monospace font such as *
// * Courier New, in a line length of 67 characters. *
// * *
// * The rest of this header addresses these topics: *
// * *
// * *
// * * The "rope" as represented in this code *
// * * Configuring this code for testing *
// * *
// * *
// * THE "ROPE" AS REPRESENTED IN THIS CODE -------------------- *
// * *
// * The rope is defined as the binary tree of its nodes, where *
// * each node points to up to SEGMENT_MAX_LENGTH characters of *
// * the string. Each node of the binary tree contains: *
// * *
// * *
// * * A pointer to the start of the segment *
// * *
// * * The node type: *
// * *
// * + ENUnodeType.child indicates that the node is a *
// * child node of another node.
*
// * *
// * + ENUnodeType.ancestorLengthKnown indicates that the*
// * node has no parent AND that the length of the *
// * entire string is at this time, known. *
// * *
// * + ENUnodeType.ancestorLengthTooLarge indicates that *
// * the node has no parent AND that the length of the *
// * entire string exceeds a maximum value. *
// * *
// * By default, this maximum value is 2^63-1, the *
// * maximum length of an unsigned "long long" less a *
// * margin to allow for testing the length. The *
// * maximum value, however, can be set to smaller *
// * values for testing. *
// * *
// * + ENUnodeType.ancestorLengthUnknown indicates that *
// * the node has no parent AND that the length of the *
// * entire string is at this time, fully unknown. *
// * *
// * * The 64 bit unsigned string length. Note that this *
// * value may be unusable: *
// * *
// * + The length may be undetermined: here the node *
// * type will be ENUnodeType.ancestorLengthUnknown *
// * *
// * + The length may exceed long-long precision: here *
// * the node type will be *
// * ENUnodeType.ancestorLengthUnknown *
// * *
// * + The node may be a child node: here the node type *
// * will be ENUnodeType.child *
// * *
// * * The start index of the rope segment (substring) *
// * within the full string; note that in rare cases this*
// * is unknown when the string is longer than 2^64-1 *
// * characters, and the segment is located on the right *
// * of the string, this value may also be unknown. Here *
// * it is set to -1 (UNKNOWNLENGTH). *
// * *
// * * The length of the rope segment (substring) *
// * *
// * * The address of the parent of the node or NULL *
// * *
// * * The address of the left child of the node (holding *
// * characters to the left of the segment) or NULL *
// * *
// * * The address of the right child of the node (holding *
// * characters to the right of the segment) or NULL *
// * *
// * *
// * CONFIGURING THIS CODE FOR TESTING ------------------------- *
// * *
// * The following symbols may be set to configure a test of this*
// * code. *
// * *
// * *
// * * SEGMENT_MAX_LENGTH: maximum length of a rope string *
// * segment *
// * *
// * * STRING_MAX_RECORDABLE_LENGTH: maximum recordable *
// * length of a string, beyond which the string length *
// * is officially "unknown". To test whether strings *
// * whose lengths are not known, this symbol may be set *
// * to a small value *
// * *
// * * TEST_STRING_LENGTH: length of the string used to *
// * test this code *
// * *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges Started version 1 *
// * *
// * *
// * I S S U E S ----------------------------------------------- *
// * DATE POSTER DESCRIPTION AND RESOLUTION *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges To be implemented: use extra *
// * precision arithmetic for unbounded*
// * strings *
// * *
// * *
// ***************************************************************

// ***** Standard includes ***************************************

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <stddef.h>

// ***** Configuration *******************************************

#define SEGMENT_MAX_LENGTH 32
#define STRING_MAX_RECORDABLE_LENGTH 1024 // Set to 2^63-1 for
// actual use
#define TEST_STRING_LENGTH 2000

// ***** Macros **************************************************

// --- Statement macro to handle errors
#define ERRORHANDLER(strMessage) \
{ \
printf("%s\n", (strMessage)); abort(); \
}

The usual idiom for a macro whose body is to me almost a statement is:

#define ERRORHANDLER(strMessage) \
do { \
printf("%s\n", (strMessage)); abort(); \
} while(0)

Note that there is no ; at the end. Thus when you later write (as you
do)

if (CONDITION)
ERRORHANDLER("Some text");

you get a correct if clause. You version works in this context but
the ; adds an empty statement that means, amongst other things, that
you can't add and else clause to the if.
// --- Expression macro to perform malloc
#define MALLOC_(bytesNeeded, cast) \
( (cast)(malloc((bytesNeeded))) )

What benefit is this? It is no shorter, and means the reader must keep
this definition in mind as they read (or keep referring to it). In
general the even shorter form where one writes:

ptr = malloc(sizeof *ptr);

or

ptr_to_lots = malloc(how_many * sizeof *ptr_to_lots);

is better, in my opinion.
// --- Statement macro to perform malloc with error checking
#define MALLOC(ptr, bytesNeeded, cast, purpose)
{ \
if (((ptr) = MALLOC_((bytesNeeded),(cast))) == NULL)) \
{ \
printf \
("Can't get storage: purpose was: %s\n", (purpose)); \
errorHandler("Malloc failed"); \
} \
}

Personally, I feel this is enough to put into a function. C99 has
inlined functions which overcome almost all of the problems with this
sort of macro.
// --- Symbols
#define KNOWNLENGTH 0
#define UNKNOWNLENGTH -1
#define ABSURDLENGTH -2

I'd make this an enum, too though that is very much a style issue.

I'm going to leave the code for the moment. There is likely to be new
version as soon as you show it to a compiler (there are all sorts of
undefined identifiers and syntax errors which make it hard to know
what exactly you mean).

<snip>
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top