Hi all, I am working with the TI TUSB3200, trying to modify their example code for our own USB device. USB requires many tables which start with a length byte. I would like to use the sizeof operator to calculate this for me, as shown here:
byte code rictest[] = { sizeof(rictest), 1, 2 };
warning C198: sizeof returns 0
The reason that sizeof doesn't do what you want is because the object you are requesting the size of isn't defined, yet. So, its size is unknown. If you change your code to the following:
byte code rictest[12] = { sizeof(rictest), 1, 2 };
This is an example of an incomplete type. The C language does not support it so why should a compiler. You can only do this with pointers to incomplete types, but then of course you only get the size of the pointer.
a dumb (maybe) suggestion: Declare the array twice sArrName[] = {...}; ArrName[] = {sizeof (sArrName), ...}; This could be done even simpler with a macro containing the entire array save the first statement. Erik
Or, just create the array with an empty first element:
unsigned char array [] = { 0, 1, 2, 3, 4, ... };
. . . array[0] = sizeof (array); . . .
Sorry guys, I didn't spell out all my requirements. The table is in read-only ROM, so I can't modify the first element later on. I want to experiment adding and removing entries to these tables, so the length will vary. It seems very labour intensive (and error-prone) to manually count the bytes each time. I was trying to think of some way to make a macro to somehow do a dummy define on the data to work out the size, and then do the real define once it knows the answer, but I can't think of a way to do this without really creating the table (so I would end up with two copies of it). I suppose the last resort solution would be to write a pre-processor in Visual Basic to construct the C source file for me...
Jon suggested "If you are creating the VID and PID tables for USB, you can create structs for each of these and then you may use the sizeof operator to initialize the VID or PID structure." Thanks for the suggestion Jon, but it is the mainly the configuration descriptor (which is huge, about 280 bytes), which I am concerned about. I am slowly coming to the conclusion that I will have to write a seperate program to dynamically generate a .c file and matching .h file.
You could do something like...
#include <string.h> static unsigned char code descriptor [] = { 1,2,3,4,5,6,7 }; unsigned char xdata xdescriptor [1 + sizeof (descriptor)] = { sizeof (descriptor), }; void main (void) { memcpy (&xdescriptor[1], descriptor, sizeof (descriptor)); }
"read-only ROM" What other sort of ROM is there?! ;-)
Can you make use of strings?
#define RICTEST_STR "\x1\x2" struct rictest_t { byte size; char str[sizeof(RICTEST_STR)]; }; struct rictest_t rictest = { sizeof(struct rictest_t), RICTEST_STR};
Andrew said: : "read-only ROM" : : What other sort of ROM is there?! ;-) What's wrong with a bit of redundancy? :~) It fits in well with "LCD display", "DOS operating System", "PIN number", "USB bus" ...
"What's wrong with a bit of redundancy? :~)" It's not redundancy, it's tautology! "It fits in well with 'LCD display', 'DOS operating System', 'PIN number', 'USB bus' ... Yes, it's exactly the same error - they're all just as bad! ;-)
Hmm, I think you can make use of how Keil arranges/places variables in memory. They are not arranged in order of declaration, they are arranged alphabetically. So, if you declare: const unsigned char myarray[] = {1,2,3,4}; const unsigned int amyarraysize = sizeof(myarray) + 2/*include size of amyarraysize */); in one file, with no other declarations. amyarraysize will appear as the first in memory, followed by myarray. (Of cause myarray itself should no longer contain the size ...). Remember to move the pointer to amyarraysize, when copying. Now, Im not sure that it will always work, but I think so. If you really want to be sure, use the SECTIONS(?NC?YOURFILENAME?NCONST (addr)) to place it to a fixed place in memory Best regards Niels Sejersen
A very neat trick Niels, I'll remember that in future. It would probably be possible to base a solution on this trick. I now find that externally linked modules needed to know the length also, currently it is defined in a .H file. I could modify the external modules to read the length from the array, but I might just stick with writing a utility to auto-genaerate the .c and .h files, with the length calculated automatically and inserted into the source. This will make the source easier to read (& understand) when the project is complete.
It is probably worth creating some validation code to make sure that things are located in memory in the order you wish. The symbol table manager uses a hash algorithm that may be changed in the future, so be careful using tricks like this. I'm not saying you shouldn't do this. I'm just saying that you should be careful. Jon
Hmm, I think you can make use of how Keil arranges/places variables in memory. They are not arranged in order of declaration, they are arranged alphabetically. This is a painfully bad idea. Not only is it completely unportable, and needlessly so, it will even break with the Keil tool-chain if you tell C51 to keep varables in order via the ORDER directive. Write a program to generate the .c and .h files. Then it could be used with other tools.