• C

How to allocate 1.44M space in DOS?

Hello,

I want to make space for a whole 1.44Mega bytes? but the limit is 64k,

How can I?

Zouying
wenfengAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jhanceCommented:
What compiler are you using?  There are several possibilibites:

1) You are using a compiler that supports the HUGE memory model.  In that case using a special huge memory allocator you can do it.  Borland C supports this.

2) You are using a compiler that supports a DOS EXTENDER like DOS4GW or PharLap.  You need to change the mode to build such an app.  WATCOM C and ZORTECH C support this.

3) If neither of the above are true, you need to do it the hard way.  You have to manage the DS (data segment) register yourself and allocate multiple 64K chunks until you get the amount you need.  Microsoft C supports this.
0
KangaRooCommented:
Erm, you can not allocate more then ~600 Kb unless you use a DosExtender or Expanded/extended memory
0
wenfengAuthor Commented:
I am using Visual C++ 1.52. I am sorry to reject me. You answer is too general. I need some more detailed answers.

the maximam size is 2 power 16, which is 64K. When I try to _fmalloc(65536). it gives a warning error. only 32K is acceptable. How do I allocate 64K? the parameters of _fmalloc is size_t, size_t means what?


Obviously, I can only allocate 1.44M/4, which is about 380k, each time. (right?)
So I manupulat each 64K ( or 32K) one by one?

Thanks

0
The Lifecycle Approach to Managing Security Policy

Managing application connectivity and security policies can be achieved more effectively when following a framework that automates repeatable processes and ensures that the right activities are performed in the right order.

KangaRooCommented:
Which leaves you with 3... jhance?
0
jhanceCommented:
I'll have to assume you know what I mean by "memory model" in the x86 CPU architecture.


First, what MS VC++ memory model are you using?  It must be LARGE so that you can have a data segment > 64K.  Otherwise, the model used by the compiler requires that ALL DATA fit in a single 64K block.  


Allocating a full 64K block of memory on a real-mode x86 is tricky. The block MUST START ON A PAGE BOUNDARY so that the full range of the 64K can be accessed without changing the DS register.  Following is a code snippet that I've used to accomplish this in the past:

(BTW, one other problem.  On a 16-bit CPU the largest number you can pass to malloc is 65535.  Why is this?  Please imagine how to represent the number 65536 in binary.  It's 10000000000000000 (0x10000) and not 1111111111111111 (0xFFFF).  Since you can only pass an int to malloc and it's friends, you're stuck with 65535 as the maximum you can request.  The good news is that you really get the full 64K you want.  There are no malloc() runtime libraries that allocate with 1-byte resolution.  Most are 8 or 16 byte chunks.)

/* For Segmented processors (i.e. 8088 and family)   */
/* the 64K memory space for the 64K block MUST be aligned */
/* on a segment boundary.  It would be easier to use */
/* HUGE pointers but that would be much slower.      */

if ( (int) mem_ptr != 0)
 {
    mem_ptr = calloc(65535,sizeof(unsigned char));
    if (mem_ptr == NULL)
     {
      printf("calloc returned null - not enough RAM to correct\n");
      exit(1);
     }

  if ( (int) mem_ptr != 0)
   {
    while( (int) mem_ptr != 0)
     {
      mem_ptr--;
     }
   }

    /*  Now we have a good pointer but see if there is still   */
    /* enough RAM left to run                                  */
    tmp_ptr = calloc(65535,sizeof(unsigned char));
    if (tmp_ptr == NULL)
     {
      printf("calloc returned null - not enough RAM to run\n");
      exit(1);
     }
    printf("Buffer is aligned at %p\n",mem_ptr);
 }
else
 {
  printf("Memory pointer is OK at %p\n",mem_ptr);
 }
0
wenfengAuthor Commented:
I tried the codes:


#include <stdio.h>
#include <conio.h>
#include <malloc.h>

int main()
{
      char* string = (char*)calloc(65535, sizeof(char));
      
      if (string == NULL)
            printf("Can't allocate");
      else
            printf("OK");
      
      getch();      
      return 0;
}

it returned can't allocate. That's the only program. but if I change to 60000, it's OK.
0
jhanceCommented:
KangaRoo, this one's all yours....
0
jhanceCommented:
Here, I'll repeat this VERY IMPORTANT POINT!!!


---------------------------------------
I'll have to assume you know what I mean by "memory model" in the x86 CPU architecture.


First, what MS VC++ memory model are you using?  IT MUST BE THE _LARGE_ MEMORY MODEL so that you can have a data segment > 64K.  Otherwise, the model used by the compiler requires that ALL DATA fit in a single 64K block.  
---------------------------------------

This is why you cannot allocate more than about 60K in your program.  Since ALL of the DATA objects in your program must fit within a SINGLE 64K block, there is not enough room for a full 64K allocation and the other data your program needs to run.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
LucHoltkampCommented:
Even then, you can never allocate exactly 64 k, simply because the heap-manager needs some space for a size-indicator and pointer to next/previous block, al this must fit together with your allocated block into 64k.
And even then, the 16 bit DOS mode limits you to 640kb of RAM to fit everything, program, OS and heap... In practice, you can't allocate more then ~500 kB
So the only way out of this is:
* switching to 32 bit console (works exacly as DOS, the difference however is that it's full 32 bits and requires Win95+) Every win32 compiler supports this. This is the easiest solution.
* using a DOS-Extender
0
jhanceCommented:
wenfeng,

You still alive?

I have some more information.  I don't think that you can do this in VC++ 1.52 using the standard memory allocator.  THe example I posted above does indeed work in Borland C++ and others but the malloc on VC++ seems to have an odd quirk.  When allocating space close to the end of the DS limit (i.e. the OFFSET is close to 0xFFFF), it rolls over to a new and non-contiguous) DS segment value before the entire 64K bytes of the segment have been allocated.  If you example the DS:OFFSET values obtained with the FIRST call to malloc(), you will get a value other than 0x0000 for the OFFSET.  In most cases on my machine, I get a value of DS:0x16.  Since the range of offset values for any DS value is 0x0000-0xFFFF, starting with DS:0x16 leaves only 0x10000 - 0x16 (or 65514) bytes available in that segment.  My code above attempts to get around this by allocating small amounts at a time until the DS rolls over to the next segment and gives a DS:0x0000 value.  At this point, the entire segment is free and clear and you can allocate a full 64K segment in one chunk.  Borland's malloc does this as does my copy of Symantec C++.  Microsoft's malloc in VC++ 1.52 does not.

One solution might be to use a HUGE pointer and use the huge allocator.  With it, you can allocate up to 1MB (although in reality you can't get more than the available DOS space - the amount already used.)  Once you get this huge pointer, you should be able to convert it to a DS:OFFSET (i.e. a FAR POINTER) that has a 0x0000 offset.  You can then use this pointer to access the entire 64K segment.

Now that I've broken out my dusty old copy of VC++ 1.52 and installed it, I'll see if I can post an example of how to do this.  I still think you are not understand the relationship of the C pointers and address you are making and their underlying real-mode x86 representations.  The x86 segmented architecture is a mess and until 32-bit programming became common, programmers had to deal with this problem all the time.
0
jhanceCommented:
wenfeng,

OK, here is code that works with VC++ 1.52 and allocates a 64K block.  In fact, you can allocate a block larger than 64K but it's then a real pain to work with due to the limitation of the size of a pointer in DOS mode programming.  This program uses _dos_allocmem() to get it's memory so that we can get a non-offset block of memory:


/*

   Compile with LARGE memory model only:

   cl /AL test.cpp

*/

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

void printfp(char *p);

int main(int argc, char *argv[])
{
        char far *p;
        size_t size;
        unsigned seg;
        long i;

        printf("Hello\n");
        if(argc < 2){
                printf("No args...\n");
                printf("usage: test <size to allocate in K (1024) byte chunks>\n");
                return 1;
        }

        /* Get the size in KB from the command line */
        size = (size_t)((atoi(argv[1])/16)*1024);

        printf("Requesting %u paragraphs, %ld bytes\n", (unsigned)(size), ((long)size)*16L);

        /* Use the _dos_allocmem() function to get a full sized block */
        /* This function works in paragraph (i.e. 16 byte) sized chunks */
        /* so divide the size needed by 16 */
        if(_dos_allocmem((unsigned)(size), &seg) == 0){
                printf("_dos_allocmem() is OK.  seg = 0x%0X\n", seg);

                /* Make a char far * to this so we can access it */
                p = (char far *)_MK_FP(seg, 0);
                printfp(p);

                /* Use the pointer to fill the block with junk */
                /* Note that the total range access using this
                   method cannot exceed 64K bytes regardless of
                   the allocated blocks size.  The pointer *(p+i)
                   is still a far * and is limited to a single segment */
                for(i=0; i<0x10000L; i++){        
                        *(p+i) = (unsigned char)(i%256);
                }

                /* Done with the memory, free it */
                _dos_freemem(seg);
        }
        else{
                printf("_dos_allocmem() ERROR\n");
        }

        return 0;
}

void printfp(char *p)
{
        printf("p = %0X:%0X\n", _FP_SEG(p), _FP_OFF(p));
}
0
wenfengAuthor Commented:
Thanks for your great patience
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.