I declare a variable unsigned char bdata Kde in a.c.
[in file a.c] unsigned char bdata Kde;
[in file b.c] #include <stdio.h> ..... extern unsigned char bdata Kde; sbit testbit=Kde^1; void main(void) {......}
Sfr and sbit's are special. They refer to hardware registers which are by definition global. Thus, Keil (at least if my memory serves me correctly) allows one to define the same named object in a header file and pretend that it is auto-externed/defined as needed. This is the only way files like reg552.h etc. could work. E.g.
/* Foo.h */ sfr r_port0 = 0x80;
I have now tried it and it does work, but I did have to make a small change:
[in file a.c] bdata unsigned char Kde; sbit testbit=Kde^1;
#include <stdio.h> ..... extern bdata unsigned char Kde; extern bit testbit; void main(void) {......}
Note that you are changing the type of 'testbit' from an sbit to a bit. How does the linker deal with this? This is very odd looking from a C standpoint and I wouldn't do it this way. Also, I cannot believe
sbit testbit=Kde^1;
C51 is a bit strange with regard to bit memory, sbit etc. Of course, sbit is totally non-C. This thread contains some grumbles from me and some explanations from Keil: http://www.keil.com/forum/docs/thread1291.asp Yes, I agree, it is all bad practice and best avoided. Bit fields within structures is a much more natural and C compliant way to reference individual bits that belong in a 'set', but C51 does not emit efficient code for this. A variable residing in bdata and accessed by individual sbit addresses provides a way of efficiently accessing 1-bit fields withing a "structure". When fast and compact code is required, it is necessary to make use of bdata variables accessed via sbit definitions. The code I gave earlier in this thread is pretty much exactly what is in Appendix F of the C51 manual, it does compile and it seems to work. Actually, the type of testbit is not getting changed because bit is not a type but a memory area (like data). Perversely, C51 does not allow variables located in bit memory to have a type.
"I thought that sbits required a upper data space (e.g. DATA address 128 - 255) address to be assigned to them." It is with trepidation that I dare to suggest that you're wrong there, Mark. This was one of the first stumbling blocks which I fell over when I started using Keil - if you search back a couple of years, I probably moaned about it here! (probably along the lines, "you can tell it catches lots of people out by the way there's a special section in the manual!") Anyway, as I understand it, sbit is the means that Keil uses to give a name to a specific bit (hey - maybe I just hit on the meaning of the 's' there!) - whether it's in a hardware register, or a bdata variable. Effectively, sbit forms the definition of a bit "variable" bit, on the other hand, does not define the location of the "variable" - it simply says, "this is a single bit" Therefore, an extern must always use bit rather than sbit; repeating the sbit definition causes (if I remember correctly) a "multiple definition" Linker error.
Unbelievable! I never would have thought that sbit was meant for anything other than an sfr bit, that is DATA addresses > 0x80. I am sorry and disheartened about being wrong on this. I just assumed consistency where there isn't.
"I just assumed consistency where there isn't." Yes; as both Graham and I have noted, Keil's doesn't appear a particularly Elegant Solution...
Keil's doesn't appear a particularly Elegant Solution... From what I recall, the bit/sbit/bdata junk was what Intel introduced in the PL/M-51 Compiler. At the time the Keil C compiler was introduced, PL/M-51 was the de-facto standard compiler for the 8051. So, we adopted the Intel standard. These legacy language elements are sometimes difficult to kill-off or replace without breaking a lot of existing customer source code. Jon
The Buck Stops ... way over there! ;-)
I totally agree and sympathize. However, adding a feature such as
/* foo.c */ bit someBitVar = otherByteVar ^ 1; /* foo.h */ extern bit someBitVar;
...repeating the sbit definition causes (if I remember correctly) a "multiple definition" Linker error. If and only if they are defined in a bdata variable. There won't be any linker error if we do:
/*Port.h*/ . . sbit bTest =P3^2; . .
Yes - I think that's the inconsistency Mark was referring to