int const * ptr2ci; // a nonconst pointer to const object, right?
int * const cptr2i; // const pointer to nonconst object
If comments above are valid, then shouldn't near pointer to nonnear object be defined like this
int * near nptr2i;
I think this ^^ should mean that ptr is to be placed to __SHORT_SEG and ptr should be able to address all 64k addresses.
And this pointer
int near * ptr2ni;
could be placed anywhere and should be able to address only objects in __SHORT_SEG (addresses 0..0xFF).
But it looks like in reality it is reversed, ptr2ni behaves like nptr2i, and opposite.
61: *ptr2ni = 5;
0000 320000 [5] LDHX ptr2ni <- pointer is 16bits wide
0003 7f [4] CLR ,X
0004 a605 [2] LDA #5
0006 e701 [3] STA 1,X
62: ptr2ni = (void*)5;
0008 ae05 [2] LDX #5
000a 8c [1] CLRH
000b 960000 [5] STHX ptr2ni <- pointer is 16bits wide
61: *nptr2i = 5;
0000 ce0000 [4] LDX nptr2i <- pointer is 8bits wide
0003 8c [1] CLRH <- widening X-> H:X
0004 7f [4] CLR ,X
0005 a605 [2] LDA #5
0007 e701 [3] STA 1,X
62: nptr2i = (void*)5;
0009 ae05 [2] LDX #5
000b cf0000 [4] STX nptr2i
Is it normal?
CW help system is bit fuzzy, it gives following example
I guess __far on the right is a typo. Also there's no int __near * i; case.
> If comments above are valid, then shouldn't near pointer to nonnear object be defined like this
The comments above are valid. But "near pointer" means that a pointer can only point
to near objects, therefore a "near pointer to nonnear object" does not exist.
There are 2 distinct things __near can define.
For a pointer type __near defines if the pointer type is a near
or far pointer. This defines if an object of that type is 1 byte or 2 bytes in size, it also defines what kind of objects can be reached with the pointer.
In this context __near is defining the type of the object.
In order to define the type of a pointer, the __near keyword must placed just after the star.
E.g.
int *__near p1;
int *__near* p2;
The type of p1 is "int *__near", the type of p2 is "int *__near*".
In the case of p2 note that p2 itself is not a __near pointer, it just happens to point to one. So the size of p2 is 2 bytes (in the small memory model).
The second, independet topic is how the object itself is accessed.The compiler can either generate direct, 8 bit accesses or 16 bit externded addresses. This part is not specific to pointer, all kind of objects can have near access.
Also (and this is different from const) the __near access is not part of the type. It only aplies to the object.
For this use of __near, the keyword must be placed before the type, or for pointers it can also be listed after the type the pointer points to (if this is not itself a pointer).
E.g.
__near int in;
__near int* ip;
__near int** ip;
// Not recommended, easely confused with a near pointer type:
int __near * ip;
Here the near defines how the variables get accessed.
In real code using __near to define the access rarely is necessary. The __near object qualification on its own does not affect how the object gets allocated, so in order to be located in the zero page the object must also be allocated into a special section. By using a __DIRECT_SEG section qualifier, the __near object access gets the default for all object in such a section.
So using __near as an object qualifier is only necessary if the
default access to the section is not the right one. In practice that should rarely, if ever be the case.
So for variables to be placed into the zero page I would always write:
#pragma push
#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE
int i;
int *__near pi = &i;
#pragma pop
The manual entry is obviously a copy paste bug.
Using __near (or const) after the int ("int __near i" or "int __near* ip") is equivalent to
using it before the int. But it is far more confusing in my opinion, so I'm always starting with the __near qualifier (for objects). Well as I said, code should rarely use __near for the object qualification anyway.
Daniel
Thanks for your comments, Daniel. My 2nd attempt.
Const modifier used with pointers can apply 1) to pointer, 2) to object pointer points to, 3) to both, to pointer and to object pointer points to.
case1
int * const ptr; // const pointer to regular object
case2
const int *ptr; // regular pointer to const object
(^^ this is equivalent to int const *ptr
case3
const int * const ptr; // const pointer to const object
Now the same 3 cases should be available with near keyword.
case1
int * near ptr; // near pointer to regular object. It means pointer should reside in zero page
case2
int near * ptr; // regular pointer to near object. Means pointer can be placed anywhere, but can point only to zero page, addresses 0..ff
case3
int near * near ptr; // near pointer to near object.
I see all 3 near cases working, but case1 and case2 are swapped. Compiler treats them as if Case1 was not a near pointer to regular object, but a regular pointer to near object. Case2 is alse reversed.
CompilerGuru wrote:
But "near pointer" means that a pointer can only point
to near objects, therefore a "near pointer to nonnear object" does not exist.
Why? I want to place most used pointer to zeropage, but pointer should be able to address whole 16bit address range. Compiler understands my needs, but it swaps the meaning of near pointer to regular with regular pointer to near.
int *__near* p2;
I'm not talking about pointers to pointers.
Also (and this is different from const) the __near access is not part of the type. It only aplies to the object.
To which object does it apply, to pointer, or to object pointer points to. I think rules should be the same like with const keyword. If keyword is closer to variable name than asterisk, then keyword applies to pointer (int * const ptr -- const pointer), else (int const * ptr or const int * ptr -- both pointers to const object). Obviously compiler uses different rules for near keyword.
In real code using __near to define the access rarely is necessary. The __near object qualification on its own does not affect how the object gets allocated,
Small memory model. Some variables near, some regular. I want to share some near variables and some regular variables among modules. I want all modules to use direct addressing with my zero page variables. Isn't it necessary to declare them with near keyword? How else compiler could decide extern variables can be accessed using direct addressing mode?
So for variables to be placed into the zero page I would always write:
#pragma push
#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE
int i;
int *__near pi = &i; // line 80 in my case
#pragma pop
I understand your pi as a near pointer to regular int. But compiler finds it problematic:
Warning : C1860: Pointer conversion: possible loss of data
main.c line 80
Error : C3400: Cannot initialize object (destination too small)
main.c line 80
Error : Compile failed
As I see it, the use of __near follows exactly the use of const for pointers.
int * const is a constant pointer, the pointer content is constant.
int * __near is a near pointer. The pointer content is 8 bit.
I see that the use of __near is different for objects (and I talk here about the object which gets qualified, not about the object refered to by a pointer) than for const, the reason is that __near in this case is not part of the type. So it follows how for example the static storage class is defined.
To make a variable static:
static int i;
static int* pi;
Note how this is different to how to make a variable const:
const int i = 0;
int * const pi = 0;
__near follows the static "model".
To access a variable with __near access:
__near int i;
__near int* pi;
So in this use case, __near does not change the type (as const does) it changes the way the variable is accessed. The type of a "__near int i" is int, just as it is int for "static int i".
By comparison the type of ci in "const int ci = 0" is const int.
In the end, when thinking about how to where to write __near the rule is simple.
It aplies to pointers only, and for those it is after the asterick.
This rule especially is valid for all kinds of pointers (pointers to pointers, function pointers, pinters to function pointers, not sure actually about pointers to members in C++, did not use those).
So while I can follow your reasoning, it's just different from what the compiler does.
About the warning/error, hmm. I don't have any CW for MCU installed here (64 bit windows is not supported by the installer for 6.2....), so I cannot try. Must be a silly bug on my side.
But when using the proper qualifier for the section pragma the __near object qualifier is not needed for the typical use case.
Is the qualifier __SHORT_SEG (and not as I guessed __DIRECT_SEG) ?
Daniel
CompilerGuru wrote:As I see it, the use of __near follows exactly the use of const for pointers.
int * const is a constant pointer, the pointer content is constant.
int * __near is a near pointer. The pointer content is 8 bit.
How near can follow const pointers, if code you suggested doesn't compile?
#pragma push
#pragma DATA_SEG __DIRECT_SEG ZERO_PAGE
int i;
int *__near pi = &i;
#pragma pop
According to "const" rules, pi should be a near pointer to any object, not only near. pi should be 16bits wide. Extern declaration of pi should tell other source modules, that they can use direct addressing to access pi. This means pi has to be placed in direct addressing range 0..ff. But pi variable should be wider than 8bits!
I see that the use of __near is different for objects (and I talk here about the object which gets qualified, not about the object refered to by a pointer) than for const, the reason is that __near in this case is not part of the type. So it follows how for example the static storage class is defined.
To make a variable static:
static int i;
static int* pi;
If near follows static rules, then why this line compiles
int * near p;
and this doesn't compile
int * static p;
Indeed something is very inconsistent.
And it makes a lot of sense for near to be a part of type. All these types make sense: near object in allocated in zero page, 8bits wide pointer to near object (pointer allocated in "far" memory), 16bits wide near pointer (allocated in zero page) to far object, near pointer to near object.
__near follows the static "model".
And I think near doesn't follow neither static nor const.
To access a variable with __near access:
__near int i;
__near int* pi;
__near int * pi; doesn't compile!
About the warning/error, hmm. I don't have any CW for MCU installed here (64 bit windows is not supported by the installer for 6.2....), so I cannot try. Must be a silly bug on my side.
But when using the proper qualifier for the section pragma the __near object qualifier is not needed for the typical use case.
Is the qualifier __SHORT_SEG (and not as I guessed __DIRECT_SEG) ?
Yes, changing __DIRECT_SEG to __SHORT_SEG makes it compiling
#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
int i;
int *__near pi = &i;
#pragma pop
But this
int i;
#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
int *__near pi = &i;
#pragma pop
doesn't compile and I believe it should if near usage was similar to const usage.
Regards,
Edward
int i;
#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
int *__near pi = &i;
#pragma pop
>doesn't compile and I believe it should if near usage was similar to const usage.
Why should this compile? It clearly wont work properly. Well I probably would have defined it to be a serios warning, but in the end pointing with a near pointer to an 16 bit address is wrong.
Just because the syntax for __near pointers happens to have a similar syntax that const or volatile for pointers does not mean it has the same semantic or the same constraints.
const pointers can point to non constant objects, __near pointers cannot point to objects allocated non near.
This example should work
int i;
#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
int *__near pi = &i;
#pragma pop
because like you said before (and I thought we agreed) that pi is a near pointer to int, not regular pointer to near int. Of course i isn't near.
BTW here what I see in manual for far keyword:
Do you see the difference???? Compiler behaviour doesn't agree not only with "const model", but even with manual! Hope you won't say me __far keyword applies backwards compared to near.
Anyway thanks.
More findings using extern declarations.
extern char c;
50: c = 1;
0000 a601 [2] LDA #1
0002 c70000 [4] STA c <-- extended addressing
extern near char nc;
51: nc = 5;
0005 6e0500 [4] MOV #5,nc <-- direct addressing
extern char * near nptr2c;
53: *nptr2c = 17;
0008 a611 [2] LDA #17
000a ce0000 [4] LDX nptr2c <-- pointer access extended
000d 8c [1] CLRH <-- pointer is 8bits wide
000e f7 [2] STA ,X
extern char near * ptr2nc;
54: *ptr2nc = 15;
000f a60f [2] LDA #15
0011 320000 [5] LDHX ptr2nc <-- pointer access extended
0014 f7 [2] STA ,X pointer is 16bits wide
extern char near * near nptr2nc;
55: *nptr2nc = 20;
0015 a614 [2] LDA #20
0017 ce0000 [4] LDX nptr2nc <-- pointer access extended
001a 8c [1] CLRH <-- pointer is 8bits wide
001b f7 [2] STA ,X
Now what is the difference between
extern char * near nptr2c;
and
extern char near * near nptr2nc;
Looks like near to the left of * is USELESS.
Is the only way to make pointers accesses direct, to declare them between some DATA_SEG pragmas? Like this
#pragma push
#pragma DATA_SEG __SHORT_SEG ZERO_PAGE
extern char * ptr2nc; // near pointer to char
extern char * near nptr2nc; // actually near pointer to near char
#pragma pop