In DOS, if you write C/C++ programs using Turbo C/C++, you will need to select a memory model for the application. The memory model basically specifies the number of segments in memory for code, data and stack and has an effect on all pointers used in the program.
Before understanding the various memory models, let us first have a look at some basic definitions:
Segment: A segment is a memory section of maximum size 64KB in DOS. Every segment will have a segment number, which is a 16-bit unsigned integer. There are 65536 such segments, ranging from 0x0000 to 0xFFFF.
Offset: An offset is a byte displacement within a selected segment. This is also a 16-bit unsigned integer ranging from 0x0000 to 0xFFFF.
Logical Address: A logical address is the complete address of a memory location. It is specified using a combination of segment number and offset and looks like SSSS:OOOO, where SSSS is the segment number and OOOO is the offset, both in hexadecimal. The logical address is 32 bits wide (16 bits for segment + 16 bits for offset).
Physical Address: The physical address is the ultimate address that the processor uses and is 20-bits wide for the 8086 or any other higher x86 processor working in 16-bit mode.
Programmers can only use logical addresses in their programs whereas the hardware uses only physical addresses. Every logical address will have a corresponding physical address. Thus, there exists a mapping of the 32-bit logical address to it’s corresponding 20-bit physical address. Clearly this is a many-to-one mapping which implies that multiple logical addresses can end up being mapped to the same physical address.
The procedure to convert a logical address (SSSS:OOOO) to it’s physical address (AAAAA) is to left shift the segment (SSSS) by 4-bits (1 hexadecimal digit) and add the offset (OOOO) to it. For example, the logical address 1111:2222 will be converted to the physical address 13332. This many-to-one mapping also has the effect that the 65536 segments overlap in memory. Each new segment starts 16 bytes after the previous one starts.
Code Segment: The segment that contains the code or instructions of the program
Data Segment: The segment that contains data belonging to the program, accessible to the program whenever it wants
Stack Segment: The segment that houses the system stack, and is automatically and extensively used while calling functions or procedures.
Based on the requirements and size of the program, we can choose any one of 6 memory models as shown below:
Model | No. of Code Segs. | No. of Data Segs. |
---|---|---|
Tiny | 1 | |
Small | 1 | 1 |
Medium | many | 1 |
Compact | 1 | many |
Large | many | many |
Huge | many | many |
From the above table, it is clear that:
- in the TINY memory model, the code, data and stack are all housed together in 1 segment. Hence the maximum file size can only be 64KB. All .COM files are of this type.
- In the SMALL memory model, the code is present in 1 segment and the data and stack in another segment. The total program size can thus be 128KB.
- In the MEDIUM memory model, the code is stored in multiple segments, but the data is housed in a single segment.
- In the COMPACT memory model, the code is housed in a single segment, but the data is stored in multiple segments.
- In the LARGE and HUGE memory models, the code as well as data can individually take up multiple segments, but still there are differences between the two, which is highlighted later on in this article.
Depending on the memory model, all pointers in the program take up one of 3 types:
- Near pointers: This is the default type in TINY, SMALL and MEDIUM memory models. The pointer stores only the offset as the segment is assumed (there is only one segment anyway). Thus, the size of the pointer is 2 bytes.
- Far pointers: This is the default type in COMPACT and LARGE memory models. The pointer stores both the segment as well as the offset and hence the size is 4 bytes.
- Huge pointers: This is the default type in the HUGE memory model. Just like far pointers, these pointers also store both segment and offaset and occupy 4 bytes, but are different from far pointers. Again, the difference is mentioned later on in this article.
In case you are not happy with the default pointer type, or do not want your pointer type to be dependent on the memory model, you may explicitly use the keywords near
, far
and huge
as follows:
char *ptr; /* Default pointer type */ char near *ptr; /* Near pointer */ char far *ptr /* Far pointer */ char huge *ptr; /* Huge pointer */
Difference between far and huge pointers:
Both far pointers and huge pointers store the segment and offset and hence occupy 4 bytes. But these are the differences:
- Huge pointers store segments and offsets in a “normalized” form. As was already mentioned, multiple logical addresses can map on to the same physical address. Comparison of far pointers is risky and unsafe since they may refer to the same memory location, but the logical addresses being compared may be different and the pointer comparison may fail. Comparison of huge pointers is safe. As part of the normalization process, generally, the segment number is maximized and the offset minimized, without changing the effective physical address. This generally changes the logical address to the form SSSS:0004.
- Arithmetic operations on far pointers only affect the offset part and the segment remains unchanged. If we continuously increment a far pointer for example, only the offset is changed and after 0xFFFF will fall back to 0000. But the segment does not change! Huge pointers do not suffer from this, and can be incremented throughout the memory range!
In conclusion, use huge pointers when:
- Pointer comparison is used.
- A single data item is stored across multiple segments. For example,
huge float marks[100000]
. Note that the memory requirement for this array is 4,00,000 bytes which is more than a segment. The entire array cannot fit within a single segment and hence it is compulsory for it to be marked huge.
Do not use huge pointers unnecessarily as they are slower than far pointers.
Related Articles
No user responded in this post