[comp.lang.c++] Borland C++ memory allocation questions

syswerda@bbn.com (Gilbert Syswerda) (11/16/90)

/*
This program compiles without errors or warnings, using the large
memory model. I have several questions.

1. The return type for sizeof() is defined in alloc.h as unsigned. If
   this is so, how can it be returning such large values?

2. Why is the size of c3 only 2 bytes?

3. Why is the size of b3 only 2 bytes, yet b3.vals 64K bytes?

4. Looking at c4, how can I define a huge class structure?

5. It would be interesting if someone would run this code under 1.01 to
   see if it does the same thing.

Caveat: I am fairly new to both C and C++. However, I do understand
Intel's segmented architecture (and expect Borland to understand it too). I
made a similar posting a couple months ago, but was pulled away for a
while. My apologies to those who attempted to answer this the last time.
*/

#include <stdio.h>
#include <alloc.h>

typedef char a1[65535];
typedef char a2[65536];    // This is *exactly* 64K worth of chars

typedef char huge a3[65537];    // Compiler complains if not declared huge
typedef char huge a4[12345678]; // Ditto

class c1 {
   public:
   unsigned long l;
};

class c2 {
   public:
   c1 vals[16383];
};

class c3 {
   public:
   c1 vals[16384];  // This is exactly 64K worth of longs
};

/* Compiler will not compile the following:
   it complains that the structure is too large. I don't know how to
   make it huge.

class c4 {
   public:
   c1 vals[16384];  // This is 64K bytes
   char ch;  // Plus one more
};
*/

void main() {

long l; // This is used to allow the compiler to do type conversion from
        // whatever sizeof is returning.
c2 b2;
c3 b3;

char a5[65536];      // 64K worth of chars
char huge a6[99999]; // more than 64K

   printf ("\n\n\n");
   printf ("   Coreleft: %ld\n",   l = coreleft());
   printf ("Farcoreleft: %ld\n\n", l = farcoreleft());

   printf ("Sizeof a1: %ld\n",   l = (sizeof (a1)));
   printf ("Sizeof a2: %ld\n",   l = (sizeof (a2)));
   printf ("Sizeof a3: %ld\n",   l = (sizeof (a3)));
   printf ("Sizeof a4: %ld\n\n", l = (sizeof (a4)));

   printf ("Sizeof a5: %ld\n",   l = (sizeof (a5)));
   printf ("Sizeof a6: %ld\n\n", l = (sizeof (a6)));

   printf ("Sizeof c1: %ld\n\n", l = (sizeof (c1)));

   printf ("Sizeof c2: %ld\n",   l = (sizeof (c2)));
   printf ("Sizeof c3: %ld\n\n", l = (sizeof (c3)));

   printf ("Sizeof b2: %ld\n",   l = (sizeof (b2)));
   printf ("Sizeof b3: %ld\n\n", l = (sizeof (b3)));

   printf ("Sizeof b2.vals: %ld\n", l = (sizeof (b2.vals)));
   printf ("Sizeof b3.vals: %ld\n", l = (sizeof (b3.vals)));
}


/* Program output


   Coreleft: 403504
Farcoreleft: 403504

Sizeof a1: 65535
Sizeof a2: 65536
Sizeof a3: 65537
Sizeof a4: 12345678

Sizeof a5: 65536
Sizeof a6: 99999

Sizeof c1: 4

Sizeof c2: 65532
Sizeof c3: 2

Sizeof b2: 65532
Sizeof b3: 2

Sizeof b2.vals: 65532
Sizeof b3.vals: 65536

*/

grimlok@hubcap.clemson.edu (Mike Percy) (11/17/90)

I couldn't get this out by mail, sorry

To: syswerda@bbn.com
Subject: Re: Borland C++ memory allocation questions
Newsgroups: comp.lang.c++
References: <60903@bbn.BBN.COM>

In comp.lang.c++ you write:

>/*
>This program compiles without errors or warnings, using the large
>memory model. I have several questions.

>1. The return type for sizeof() is defined in alloc.h as unsigned. If
>   this is so, how can it be returning such large values?

To print an unsigned you must use the unsigned format!  %u or %lu.

>2. Why is the size of c3 only 2 bytes?
 
See below...

>3. Why is the size of b3 only 2 bytes, yet b3.vals 64K bytes?
See below...

>4. Looking at c4, how can I define a huge class structure?

>5. It would be interesting if someone would run this code under 1.01 to
>   see if it does the same thing.

I've modified the code to correct some mistakes...
 

#include <stdio.h>
#include <alloc.h>

typedef char a1[65535];
typedef char a2[65536];    // This is *exactly* 64K worth of chars
// 65535 is a long constant 0x0000FFFF, when converted to integer 0xFFFF
// 65536 is a long constant 0x00010000, when converted to integer 0x0000

typedef char huge a3[65537];    // Compiler complains if not declared huge
typedef char huge a4[12345678]; // Ditto
// 65537 is a long constant 0x00010001, when converted to integer 0x0001
// didn't work out 12345678, but lop of high 16 bits and I'm sure you're
// left with 24910...
 
// See p 331 (Programming Guide 3.3.3.4
//   For a normal array, the type [to hold max. size of array] is
//   unsigned int, and for huge arrays the type is signed long.)
// Note that for a3 and a4, there is no problem with the declaration.
// The problem is that sizeof() return size_t which is unsigned int.

// Actually there is a problem -- you still don't get the space you ask
// for.  Have a look at the assembly code.  The workings of arrays of
// size > 64K is more complicated than I have time to into right now.
// The easiest thing to do is to dynamically allocate them farmalloc()
// and address them with a huge pointer.

class c1 {
   public:
   unsigned long l;
};
// ok here

class c2 {
   public:
   c1 vals[16383];
};
// ok here -- index not long, and size < 64K

class c3 {
   public:
   c1 vals[16384];  // This is exactly 64K worth of longs
};
// see above size = 64K = 0x00010000, in unsigned int = 0x0000

/* Compiler will not compile the following:
   it complains that the structure is too large. I don't know how to
   make it huge.

class c4 {
   public:
   c1 vals[16384];  // This is 64K bytes
   char ch;  // Plus one more
};
// not sure how to fix this one, will have to think about it
// but see above about handling data structures (not just arrays)
// larger than 64K
*/

void main() {

long l; // This is used to allow the compiler to do type conversion from
        // whatever sizeof is returning.
        // sorry, not quite what you needed to do.

c2 b2;
c3 b3;

char a5[65536];      // 64K worth of chars
// See above...
char huge a6[99999]; // more than 64K
// See above...

   printf ("\n\n\n");
   printf ("   Coreleft: %lu\n",    coreleft());     // rather than %ld
   printf ("Farcoreleft: %lu\n\n",  farcoreleft());

   printf ("Sizeof a1: %u\n",       (sizeof (a1)));
   printf ("Sizeof a2: %u\n",       (sizeof (a2)));
   printf ("Sizeof a3: %u\n",       (sizeof (a3)));
   printf ("Sizeof a4: %u\n\n",     (sizeof (a4)));

   printf ("Sizeof a5: %u\n",       (sizeof (a5)));
   printf ("Sizeof a6: %u\n\n",     (sizeof (a6)));

   printf ("Sizeof c1: %u\n\n",     (sizeof (c1)));

   printf ("Sizeof c2: %u\n",       (sizeof (c2)));
   printf ("Sizeof c3: %u\n\n",     (sizeof (c3)));

   printf ("Sizeof b2: %u\n",       (sizeof (b2)));
   printf ("Sizeof b3: %u\n\n",     (sizeof (b3)));

   printf ("Sizeof b2.vals: %u\n",  (sizeof (b2.vals)));
   printf ("Sizeof b3.vals: %u\n",  (sizeof (b3.vals)));
}
 
These are the results, which are exactly what is expected...

tcc -ml -w message.cpp

Turbo C++  Version 1.00 Copyright (c) 1990 Borland International
message.cpp:
Warning message.cpp 4: Constant is long
Warning message.cpp 5: Constant is long
Warning message.cpp 7: Constant is long
Warning message.cpp 8: Constant is long
Warning message.cpp 43: Constant is long in function main
Warning message.cpp 44: Constant is long in function main
Warning message.cpp 68: 'a6' is declared but never used in function main()
Warning message.cpp 68: 'a5' is declared but never used in function main()
Warning message.cpp 68: 'b3' is declared but never used in function main()
Warning message.cpp 68: 'b2' is declared but never used in function main()
Turbo Link  Version 3.0 Copyright (c) 1987, 1990 Borland International

        Available memory 26208



   Coreleft: 298768
Farcoreleft: 298768

Sizeof a1: 65535
Sizeof a2: 0
Sizeof a3: 1
Sizeof a4: 24910

Sizeof a5: 0
Sizeof a6: 34463

Sizeof c1: 4

Sizeof c2: 65532
Sizeof c3: 2

Sizeof b2: 65532
Sizeof b3: 2

Sizeof b2.vals: 65532
Sizeof b3.vals: 0

grimlok@hubcap.clemson.edu (Mike Percy) (11/17/90)

grimlok@hubcap.clemson.edu (Mike Percy) writes:

Sorry about that previous post.  I made some un-true statements.
My explanations hold true under TC++ in the C mode, but
apparently in C++ mode, sizeof works a little differently, as does
array declarations (can declare bigger arrays in C++ than in C).
 
Apparently sizeof returns unsigned long when it is used in a binary
operation with a long.  It returns unsigned int otherwise.
 
I've just gotten so used to the TC++ C mode, that my knee jerked when I
saw these (so often seen complained about in C mode).         
 
To the original poster:  The Borland documentation is obviously (was
there ever any doubt?) not perfect.  I figured this stuff out with the
-S (generate assmbly listing), if you understand the Intel architecture,
you'll be able to spot the problems.

"I don't know about your brain, but mine is really...bossy."
Mike Percy                    grimlok@hubcap.clemson.edu
ISD, Clemson University       mspercy@clemson.BITNET
(803)656-3780                 mspercy@clemson.clemson.edu