This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Unbounded Arrays and the sizeof operator

I take it using sizeof() on a array that is unbounded is a problem (I am getting sizeof returns size of type 0 warnings).

I have defined a constant array of pointers unbounded IE

#define CCHARPTR code char *
CCHARPTR numerous_strings[] =
{
"string1",
"string2",
"string3.5"
};


If I wished to know the number of entries in numerous_strings I thought I could do this

(sizeof(numerous_strings)/sizeof(CCHARPTR))


Obviously I was wrong since the compiler warns sizeof(numerous_strings) is zero. How can I get the size of this array because I would like to save time in having to write a 'magic' number for the number of numerous_strings. Sounds simple, unbounded arrays seem to be what it has issues with. Suggestions anyone?

Parents Reply Children
  • The attributes may be a bit of a problem here.

    However, when getting the size of a static array, you should normally avoid using the element data type, since that is a source of error.

    It is better to write

    #define NELEM(a) (sizeof(a)/sizeof(*(a)))
    

    If you change the data type of the array from byte to word, the NELEM define will still return the number of elements, without you having to scan through the code for inconsistencies.

  • Specifically I am using version 7.5 of the C51 compiler (this stated for odd handling of const discussion later).

    Actually that is what I was doing the issue it was having that outside the scope of the module it decided that an unbounded array has no size. So it determined the array size as 0. This means 0/sizeof(char code *) is 0. As zero divided by any number is zero. I also tried using a const definition but the compiler allocates a const in data space.
    in the header for the module

    const unsigned short number_of_numerous_strings;
    


    in the module itself.

    const unsigned short number_of_numerous_strings =
    (sizeof(numerous_strings)/sizeof(char *)));
    


    is done by creating a unsigned short in data space ... as for where the actual constant is loaded I think startup had more code added (sigh). That's incorrect because it's not a variable it's a constant. It should be treated the same as 54 or 21 with the rest of the code (IE a literal) because it is a constant (IE it doesn't change it's static inflexible unchangeable). Unfortunately with using data space for storing a constant means that constant CAN change (which is by definition against the very definition of a constant) Unfortunately constants require a type and I suspect the point where a type is used makes the compiler do some interesting things. Is const ignored by the compiler or something? I tried const on an array type before and it also was allocated to data space. This is incorrect in my point of view, it should be in CONSTANT SPACE(IE code ) or become a literal depending on if it is an array (IE character string) or a singular value (IE 123). Literal string arrays appear to be treated correctly however other array types (const list of pointers to const strings) seem to become stuffed into Data space. In any case consts can't be changed, and allocating it to data space is a questionable practice. The behavior exhibited by typical X86 compilers is to use a literal (IE the const is treated the same as an EQU in assembly and not as a variable type) for a const.

    Stephen

  • Actually that is what I was doing the issue it was having that outside the scope of the module it decided that an unbounded array has no size.

    Close but no cigar. The "it" that decided this is the C language definition, not Keil's compiler. And it would have helped if you had mentioned that you were trying to use sizeof() outside the scope of the array's definition right away.

    That's incorrect because it's not a variable it's a constant.

    Your idea of what is and isn't correct is based on incorrect assumptions. C variables qualified as 'const' don't stop being variables; in particular they don't stop having an address by which their value is accessed. A 'const'-qualified C variable is not the same as an asm EQU symbol.

  • Yes that is the unfortunate conclusion I came up with. It's hard to get around finding the size of an unbounded array outside the scope of the module. The work around I attempted was to use a const. This brings up the literal constant versus a variable constant issues you are referring too. I've seen it done BOTH ways (IE make a constant a literal and treat the constant as if it were a type defined literal). The latter is what I was expecting to happen I guess that is subjective to the compiler in the end.

    --

    So my real 'need' is to have a literal representing the number of elements of an unbounded array. This is not possible without using a const or doing some very ugly code. I was able to get around this problem in an clumsy annoying fashion (it's kind of ugly).

    The include file

    extern  code uint8_t    number_of_strings;
    


    The module definition

    code uint8_t    number_of_strings = (sizeof(numerous_strings)/sizeof(char *));
    

    As I said VERY ugly, it works but not like a literal would.

    Stephen

  • Another way to approach the problem would be with a little bit of preprocessing. Here's what I mean:

    1. List your numerous strings in a plain old text file, with one string on each line. To match the example you gave, the file would look like this:

    "string1",
    "string2",
    "string3.5"
    

    2. #include this file in your C program, thus:

    CCHARPTR numerous_strings[] =
    {
    #include "mystrings.txt"
    };
    

    3. Write a small program that counts the strings in the text file and spits out a tiny header file containing something like

    #define NUMBER_OF_NUMEROUS_STRINGS      3
    

    4. #include the header file wherever you need to.

    5. Set up your build environment (makefile, batch files, IDE, or whatever) to run the C program just before each build.

    This is probably overkill for what you are doing, but the general technique can be extremely useful in more complicated situations.

    -- Russ

  • Stephen,

    I've made this same argument before when I was flummoxed by this sort of array-size-as-a-constant problem. The problem is what the C standard allows to be considered a "true" constant (ie. one that is equivalent to a literal, can be used for sizing arrays, etc.). Here's the problem only addition and subtraction on other constants yield a constant result. Once you divide or multiply a constant by anything (including a literal), it is no longer considered a "true" constant, despite the const qualification.

    -Jay Daniel

  • Here's the problem only addition and subtraction on other constants yield a constant result.

    Whatever led you do that conclusion? It's wrong.
    Any expression involving only constants can be used in any place a constant is required. E.g.

    int array[5*30+5<<3];
    

    works just fine.

    despite the const qualification.

    That doesn't make any sense --- as const qualifiers don't make anything a constant. They make an object immutable.

  • So my real 'need' is to have a literal representing the number of elements of an unbounded array.

    That can be done, but only indirectly. You have to define the array and the length (macro) separately, then rely on either a hack (compile-time Assert()) or external tools (e.g. Lint) to tell you if they ever run out of synch. Lint will warn you right away if NELEM in

    int array[NELEM] = {
      /*...*/
    }
    

    doesn't correspond to the actual number of entries in the initializer.

  • That's very interesting regarding multiplication and division on constants. I can see why that might be a problem or compiler dependent at least. Interestingly enough my code uint8_t value comes out 27 (27 strings are size 81 / 3 bytes per string pointer == 27).
    C Side thought:

    Perhaps because of how varied C handles things an operator of elementsof() (IE return the number of elements) of something. This makes it sizeof(type) agnostic and implicitly does on the work. However again it won't work with unbounded arrays that are defined in a different module because the array size is unknown to anything but within that module. However

    const my_array_size = elementsof(my_array);
    

    would assign the const with the literal number of elements at least.
    I doubt that will ever happen however as it's not a common use to find out how many elements are in an array. The assumption is you should already know (this of course ignores unbounded arrays).

    The enumeration system I see suggested is actually possibly the best way to handle the problem for me ironically, it's still a bit of work (add a string you have to add to that enumeration statement then). I was attempting to avoid having to redefine a #define statement every time I added a string to the array. It's used to do a sanity check when referencing the array of strings. The enumeration method may be necessary to begin with (for clarity of what string is being used as the strings are more like a series of drawing commands than just plain text.)

    Stephen

  • Hans-Bernhard,

    You are correct in stating I'm wrong. I've managed to confuse issues from both C and C++ into one formulation of a wrong answer. Thanks for setting the OP right!

    -Jay Daniel

  • const my_array_size = elementsof(my_array);
    

    That's not different from the existing

    const size_t my_array_size = sizeof(my_array)/sizeof(my_array[0]);
    

    in any useful way.