Since no one mentioned DOS, forgot about the old DOS PC computers and looked at it from a general point of view. Then, very simplified, it looks like this:
Any processor has a data bus, which is the maximum amount of data that the processor can process in one command, i.e. equal to the size of its registers. The width of the data bus is expressed in bits: 8 bits or 16 bits or 64 bits, etc. This is where the term โ64-bit processorโ comes from - this refers to the data bus.
Any processor has an address bus, as well as a specific bus width, expressed in bits. Any memory location on your computer that the CPU is directly accessible to has a unique address. The address bus is large enough to cover the entire address memory.
For example, if your computer has 65536 bytes of address memory, you can cover them with a 16-bit address bus, 2 ^ 16 = 65536.
Most often, but not always, the data bus width is wider than the address bus width. Itโs nice if they are the same size, since it saves both the set of processor instructions and the programs written for it more clearly. If the CPU needs to calculate the address, it is convenient if this address is small enough to be placed inside the processor registers (often called index registers when it comes to addresses).
The non-standard keywords far and near are used to describe pointers on systems where you need to address memory beyond the normal processor address bus width.
For example, it may be convenient for a processor with a 16-bit data bus to also have a 16-bit address bus. But on the same computer, more than 2 ^ 16 = 65536 bytes = 64 KB of address memory may be required.
The processor will usually have special instructions (which are slightly slower), which allows it to address memory beyond these 64kb. For example, a CPU can split its large memory into pages n (also sometimes called banks, segments, and other such terms, which may mean different from one processor to another), where each page is 64 KB. It will then have a โpageโ register, which must be set first before accessing this extended memory. Similarly, it will have special instructions when calling / returning from routines in extended memory.
In order for the C compiler to generate the correct CPU instructions when working with such extended memory, the non-standard keywords near and far were invented. Non-standard ones, as they are, are not specified by the C standard, but they are the actual industry standard, and almost every compiler somehow supports them.
far refers to memory located in extended memory outside the address bus width. Since this applies to addresses, most often you use it when declaring pointers. For example: int * far x; means "give me a pointer pointing to extended memory." And then the compiler finds out that it must generate special instructions necessary to access such memory. Similarly, function pointers that far use generate special instructions for navigating to / from extended memory. If you did not use far , you would get a pointer to regular, addressable memory, and you would end up pointing to something completely different.
near is mainly included for consistency with far ; it refers to anything in the address memory, which is equivalent to a regular pointer. Thus, this is basically a useless keyword, except in some rare cases when you want code to be placed in standard address memory. Then you can explicitly label something as near . The most typical case is low-level hardware programming, where you write interrupt service routines. They are called by hardware from a fixed-width interrupt vector that matches the width of the address bus. This means that the interrupt service routine must be in standard addressable memory.
The most famous use of far and near is perhaps the old MS DOS computer mentioned, which is currently considered quite ancient and therefore has little interest.
But these keywords exist on more modern processors! In particular, in embedded systems, where they exist for almost every 8 and 16-bit family of microcontrollers on the market, since these microcontrollers usually have an address bus width of 16 bits, but sometimes more than 64 KB of memory.
Whenever you have a processor where you need to address memory beyond the address bus, you will need far and near . As a rule, such decisions are not approved, since it is very painful to program on them and always take into account the extended memory.
One of the main reasons that arose the need to develop a 64-bit PC was, in fact, that 32-bit PCs reached the point where their memory usage began to hit the address bus limit: they can only access 4Gb of RAM. 2 ^ 32 = 4.29 billion bytes = 4 GB. To enable the use of more RAM, then it was necessary either to use some burdensome advanced memory solution, for example, in the days of DOS, or to expand computers, including the address bus, up to 64 bits.