OK, I didn't realize that the "you" was meant to be personal rather than
generic. I'm in full agreement with you on that one. To know how to
avoid the conflicts between C and C++ he would first have to learn
enough C to be able to understand the description of those conflicts,
and from what I've seen he's got a long way to go (and what may be the
worst possible motivation for trying to go there).
Compiling it in both languages will help, since many of the differences
involve code for which a diagnostic is mandatory in one of the two
languages, and not in the other. However, there are a few differences
where that's not the case. Most notably, the value of sizeof 'a' and the
linkage of a file-scope declaration of "const int pi=3;" are different
in the two languages.- Hide quoted text -
- Show quoted text -
I fixed the project to be a C project. I had to make some minor
changes to the code to get to pre-C99 C: mostly just moving a few
variables to the beginning of their procedure.
Here is the C 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 *
// * *
// * *
// * Note that the contributions of two anonymous usenet posters *
// * are acknowledged with a grace they have failed to show. *
// * *
// * *
// * 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.ancestor indicates that the node is *
// * not a child of another node *
// * *
// * * The node length type: *
// * *
// * + ENUnodeLengthType.known indicates that the length *
// * (of the ancestor's complete string or the child *
// * subtree's substring) is known *
// * *
// * + ENUnodeLengthType.tooLarge indicates that the *
// * length exceeds the maximum value and is unknown. *
// * *
// * 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. *
// * *
// * * The 64 bit unsigned string length. Note that this *
// * value may be unusable because the length may exceed *
// * the max value: here the node length type will be *
// * ENUnodeLengthType.unknown. *
// * *
// * * 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. *
// * *
// * * 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 strings whose lengths are not known without *
// * having to generate oodlemegaterabytes of data, this *
// * value can be set to a small value. For actual use, a*
// * recommended value is 2^63-1. *
// * *
// * *
// * C H A N G E R E C O R D --------------------------------- *
// * DATE PROGRAMMER DESCRIPTION OF CHANGE *
// * -------- ---------- --------------------------------- *
// * 08 14 09 Nilges Started version 1 *
// * *
// * 08 18 09 Nilges 1. Revised implementation of *
// * statement macros per *
// * anon. *
// * 2. Using typedef instead of *
// * #define per anon *
// * 3. Using typename in cast in *
// * place of length per anon *
// * *
// * 08 19 09 Nilges Compiles successfully *
// * *
// * 08 19 09 Nilges Converted to pre-C99 C was *
// * actually C++: removed .Net stuff, *
// * moved variable decls to start of *
// * functions (yecchhh...) *
// * *
// * I S S U E S ----------------------------------------------- *
// * DATE POSTER DESCRIPTION AND RESOLUTION *
// * -------- ---------- --------------------------------- *
// * 08 18 09 Nilges To be implemented: rope names and *
// * Dewey decimal numbers of rope *
// * nodes. Routines for inspection and*
// * display of ropes. Code *
// * instrumentation of debug displays.*
// * *
// * 08 14 09 Nilges To be implemented: use extra *
// * precision arithmetic for unbounded*
// * strings, representing big nums as *
// * big strings but in a big base such*
// * as 256 for chars & 32768 for *
// * wchars. *
// * *
// * *
// * ----------------------------------------------------------- *
// * *
// * The scientific industry has its exact counterpart in the *
// * kind of minds it harnesses: they no longer need to do *
// * themselves any violence in becoming their own voluntary and *
// * zealous overseers. Even if they show themselves, outside *
// * their official capacity, to be quite human and sensible *
// * beings, they are paralysed by pathic stupidity the moment *
// * they begin to think professionally. *
// * *
// * - T. W. Adorno, Minima Moralia, 1948 *
// * *
// * *
// ***************************************************************
// ***** 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 UNKNOWN_START_INDEX -1
// ***** Macros **************************************************
// * *
// * Macros are of two types: *
// * *
// * *
// * * Statement macros can be used anywhere a C statement *
// * is valid. They are surrounded by curly braces, prefixed*
// * with do, and suffixed with while(0). When used, *
// * statement macros must be followed with a semicolon. *
// * Their names are suffixed with _STMT. *
// * *
// * * Expression macros can be used anywhere a C expression *
// * is valid. Their definitions are surrounded by round *
// * parentheses. Their names are suffixed with _EXP. *
// * *
// * *
// ***************************************************************
// --- Statement macro to handle errors
#define ERRORHANDLER_STMT(strMessage) \
do { \
printf("%s\n", (strMessage)); abort(); \
} while(0)
// --- Expression macro to return smaller value
#define MIN_EXP(value1, value2) \
( (value1) < (value2) ? (value1) : (value2) )
// --- Expression macro to perform malloc
#define MALLOC_EXP(typeName, mallocSize) \
( (typeName)(malloc(mallocSize)) )
// --- Statement macros to perform malloc with error checking
// Allocate using a type
#define MALLOCTYPE_STMT(ptr, mallocType, mallocPurpose) \
do { \
MALLOCSIZE_STMT(ptr, \
mallocType, \
sizeof(mallocType), \
mallocPurpose); \
} while(0)
// Allocate using a size
#define MALLOCSIZE_STMT(ptr, \
mallocType, \
mallocSize, \
mallocPurpose) \
do { \
if (((ptr) = MALLOC_EXP(mallocType, mallocSize)) \
== \
NULL) \
{ \
printf \
("Can't get %d bytes of storage\n", (mallocSize)); \
printf \
("My purpose was: %s...sorry it didn't work out\n", \
(mallocPurpose)); \
ERRORHANDLER_STMT("Malloc failed"); \
} \
} while(0)
// ***** Rope definition *****************************************
enum ENUnodeType { child, ancestor };
enum ENUnodeLengthType
{
known, tooLarge
};
typedef struct TYPropeNode ROPE;
typedef ROPE * Rope;
struct TYPropeNode
{
enum ENUnodeType enuNodeType;
enum ENUnodeLengthType enuNodeLengthType;
char * ptrNodeCharacters;
unsigned long long ulngStringLength;
unsigned long long lngSegmentStartIndex;
unsigned int uintSegmentLength;
Rope ptrParent;
Rope ptrLeft;
Rope ptrRight;
};
// ***** Procedures **********************************************
// ---------------------------------------------------------------
// Create a rope node
//
//
Rope mkRopeNode
(char * ptrNodeCharacters,
long long lngSegmentStartIndex,
unsigned int uintSegmentLength,
Rope ptrParent,
Rope ptrLeft,
Rope ptrRight)
{
Rope ptrNewNode = (Rope)NULL;
MALLOCTYPE_STMT(ptrNewNode, Rope, "Allocate a rope node");
(*ptrNewNode).ptrNodeCharacters = ptrNodeCharacters;
(*ptrNewNode).enuNodeType =
ptrParent == NULL
?
ancestor
:
child;
(*ptrNewNode).lngSegmentStartIndex = lngSegmentStartIndex;
(*ptrNewNode).uintSegmentLength = uintSegmentLength;
(*ptrNewNode).ptrParent = ptrParent;
(*ptrNewNode).ptrLeft = ptrLeft;
(*ptrNewNode).ptrRight = ptrRight;
(*ptrNewNode).ulngStringLength =
uintSegmentLength
+
(ptrLeft != NULL ? (*ptrLeft).ulngStringLength : 0)
+
(ptrRight != NULL ? (*ptrRight).ulngStringLength : 0);
return ptrNewNode;
}
// ---------------------------------------------------------------
// Calculate next start index on behalf of mkRope()
//
//
long long mkRope_calcStartIndex(long long lngOld,
unsigned int uintOffset)
{
unsigned long long ulngNew;
if (lngOld == UNKNOWN_START_INDEX) return UNKNOWN_START_INDEX;
ulngNew = lngOld + uintOffset;
if (ulngNew <= STRING_MAX_RECORDABLE_LENGTH)
return (long long)ulngNew;
return UNKNOWN_START_INDEX;
}
// ---------------------------------------------------------------
// Make rope
//
//
Rope mkRope
(Rope ptrParent,
char * ptrSourceChars,
long long lngStartIndex,
unsigned long long ulngStringLength)
{
Rope ptrRopeNode;
Rope ptrLeft;
Rope ptrRight;
unsigned int uintNodes;
unsigned int uintDoubleSegmentLength;
ptrLeft = NULL; ptrRight = NULL;
if (ulngStringLength <= SEGMENT_MAX_LENGTH)
uintNodes = 1;
else
{
if (ulngStringLength
<=
(uintDoubleSegmentLength = SEGMENT_MAX_LENGTH << 1))
uintNodes = 2;
else
uintNodes = 3;
}
ptrRopeNode =
mkRopeNode
(// ----- Pointer to source chars -----------------------
(uintNodes > 1
?
ptrSourceChars + SEGMENT_MAX_LENGTH
:
ptrSourceChars),
// ----- Parent segment start index --------------------
(mkRope_calcStartIndex
(lngStartIndex,
uintNodes > 1 ? SEGMENT_MAX_LENGTH : 0)),
// ----- Parent segment length (screw you anon) --------
(unsigned int)
(uintNodes > 1
?
MIN_EXP((ulngStringLength - SEGMENT_MAX_LENGTH),
(SEGMENT_MAX_LENGTH))
:
ulngStringLength),
// ----- Parent's own parent or null -------------------
ptrParent,
// ----- Left child node exists when segments > 1 ------
(uintNodes > 1
?
(ptrLeft = mkRopeNode
(ptrSourceChars,
lngStartIndex,
SEGMENT_MAX_LENGTH,
NULL, NULL, NULL))
:
NULL),
// ----- Right child node exists when segments > 1 ----
(uintNodes > 2
?
(ptrRight = mkRope
(NULL,
ptrSourceChars
+
uintDoubleSegmentLength,
mkRope_calcStartIndex
(lngStartIndex, uintDoubleSegmentLength),
SEGMENT_MAX_LENGTH
-
uintDoubleSegmentLength))
:
NULL));
if (ptrRopeNode != NULL)
{
(*ptrRopeNode).ptrLeft = ptrLeft;
(*ptrRopeNode).ptrRight = ptrRight;
if (ptrLeft != NULL)
(*((*ptrRopeNode).ptrLeft)).ptrParent =
ptrRopeNode;
if (ptrRight != NULL)
(*((*ptrRopeNode).ptrRight)).ptrParent =
ptrRopeNode;
(*ptrRopeNode).ulngStringLength = ulngStringLength;
}
return ptrRopeNode;
}
int main()
{
printf("Unlimited strings in basic C");
// ***** Insert test code *****
return 0;
}