Can I put constant string arrays in a header file

Discussion in 'C Programming' started by Tobias Blass, Apr 8, 2011.

  1. Tobias Blass

    Tobias Blass Guest

    Hi,
    I'm currently implementing a string lookup table, mapping error numbers to
    human readable strings. So my question is: Can I put the strings in a header
    file, or will I end up with N exact copies of this array (N being the number
    of inclusions of this file). I use gcc on Linux, so if anyone can tell me that
    gcc will optimise N-1 copies of the array out I'm happy with that, too.

    /* error.h */
    #ifndef ERROR_H
    #define ERROR_H

    const char *errstrs[]={
    "first error",
    "second error",
    ...
    };
    #endif
    Tobias Blass, Apr 8, 2011
    #1
    1. Advertising

  2. Tobias Blass

    Ian Collins Guest

    On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    > Hi,
    > I'm currently implementing a string lookup table, mapping error numbers to
    > human readable strings. So my question is: Can I put the strings in a header
    > file, or will I end up with N exact copies of this array (N being the number
    > of inclusions of this file).


    There will only be one copy.

    --
    Ian Collins
    Ian Collins, Apr 9, 2011
    #2
    1. Advertising

  3. Ian Collins <> writes:
    > On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >> Hi,
    >> I'm currently implementing a string lookup table, mapping error numbers to
    >> human readable strings. So my question is: Can I put the strings in a header
    >> file, or will I end up with N exact copies of this array (N being the number
    >> of inclusions of this file).

    >
    > There will only be one copy.


    The code in question is:

    /* error.h */
    #ifndef ERROR_H
    #define ERROR_H

    const char *errstrs[]={
    "first error",
    "second error",
    ...
    };
    #endif

    There won't be one copy per inclusion, because of the header guards,
    but you don't want a *definition* in a header file. If the header
    is included in two or more translation units that are linked into
    a single program, you might get multiple copies of the strings,
    or you might just get a link error. (I'm not quite sure what the
    language permits or requires here, but don't do it.)

    Here's what I came up with. Note that it makes errstrs a pointer
    rather than an array, but you can still refer to errstrs[0],
    errstrs[1], etc. If you make it an array, it means that client code
    can figure out how many elements there are, but it also means that
    you have to specify the length in the declaration and recompile if
    it changes.

    Note that identifiers starting with 'E' are reserved, so I changed
    the include guard macro name.

    /* error.h */
    #ifndef H_ERROR
    #define H_ERROR

    const char *const *const errstrs;

    #endif

    /* error.c */
    #include "error.h"

    static const char *const error_strings[] = {
    "first error",
    "second error"
    };

    const char *const *const errstrs = error_strings;

    Yes, that's a lot of "const"s. It means that client code
    can't modify the top-level pointer, any of the pointers in the
    error_strings array, or any of the error strings themselves.

    It might be simpler for error.h to declare a function that takes an int
    and returns a pointer to the error message.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 9, 2011
    #3
  4. Tobias Blass

    Ian Collins Guest

    On 04/ 9/11 12:18 PM, Keith Thompson wrote:
    > Ian Collins<> writes:
    >> On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >>> Hi,
    >>> I'm currently implementing a string lookup table, mapping error numbers to
    >>> human readable strings. So my question is: Can I put the strings in a header
    >>> file, or will I end up with N exact copies of this array (N being the number
    >>> of inclusions of this file).

    >>
    >> There will only be one copy.

    >
    > The code in question is:
    >
    > /* error.h */
    > #ifndef ERROR_H
    > #define ERROR_H
    >
    > const char *errstrs[]={
    > "first error",
    > "second error",
    > ...
    > };
    > #endif
    >
    > There won't be one copy per inclusion, because of the header guards,
    > but you don't want a *definition* in a header file. If the header
    > is included in two or more translation units that are linked into
    > a single program, you might get multiple copies of the strings,
    > or you might just get a link error. (I'm not quite sure what the
    > language permits or requires here, but don't do it.)


    Bugger, I didn't notice there was one to few consts! As you say, one
    good reason not to do this!

    --
    Ian Collins
    Ian Collins, Apr 9, 2011
    #4
  5. Ian Collins <> writes:

    > On 04/ 9/11 12:18 PM, Keith Thompson wrote:
    >> Ian Collins<> writes:
    >>> On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >>>> Hi,
    >>>> I'm currently implementing a string lookup table, mapping error numbers to
    >>>> human readable strings. So my question is: Can I put the strings in a header
    >>>> file, or will I end up with N exact copies of this array (N being the number
    >>>> of inclusions of this file).
    >>>
    >>> There will only be one copy.

    >>
    >> The code in question is:
    >>
    >> /* error.h */
    >> #ifndef ERROR_H
    >> #define ERROR_H
    >>
    >> const char *errstrs[]={
    >> "first error",
    >> "second error",
    >> ...
    >> };
    >> #endif
    >>
    >> There won't be one copy per inclusion, because of the header guards,
    >> but you don't want a *definition* in a header file. If the header
    >> is included in two or more translation units that are linked into
    >> a single program, you might get multiple copies of the strings,
    >> or you might just get a link error. (I'm not quite sure what the
    >> language permits or requires here, but don't do it.)

    >
    > Bugger, I didn't notice there was one to few consts! As you say, one
    > good reason not to do this!


    I think you may be confusing C and C++ here. The presence of a "top
    level" const makes all the difference in C++ (well it did that time I
    read a C++ reference manual) but it does not make any difference to how
    the objects may or may not get merged in a C program.

    I can't find any text that describes what it means in C to have more
    that one external definition for an object. I thought there was a "one
    definition rule" but if so I can't find it at the moment.

    --
    Ben.
    Ben Bacarisse, Apr 9, 2011
    #5
  6. Ian Collins <> writes:
    > On 04/ 9/11 12:18 PM, Keith Thompson wrote:
    >> Ian Collins<> writes:
    >>> On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >>>> I'm currently implementing a string lookup table, mapping error
    >>>> numbers to human readable strings. So my question is: Can I put the
    >>>> strings in a header file, or will I end up with N exact copies of
    >>>> this array (N being the number of inclusions of this file).
    >>>
    >>> There will only be one copy.

    >>
    >> The code in question is:
    >>
    >> /* error.h */
    >> #ifndef ERROR_H
    >> #define ERROR_H
    >>
    >> const char *errstrs[]={
    >> "first error",
    >> "second error",
    >> ...
    >> };
    >> #endif
    >>
    >> There won't be one copy per inclusion, because of the header guards,
    >> but you don't want a *definition* in a header file. If the header
    >> is included in two or more translation units that are linked into
    >> a single program, you might get multiple copies of the strings,
    >> or you might just get a link error. (I'm not quite sure what the
    >> language permits or requires here, but don't do it.)

    >
    > Bugger, I didn't notice there was one to few consts! As you say, one
    > good reason not to do this!


    Hmm? I wasn't referring to the consts, just that defining objects
    in header files is a bad idea. It's better to *declare* the
    object in the header and *define* it in the corresponding .c file.
    (Or, perhaps even better, to declare a function that gives you the
    same information.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 9, 2011
    #6
  7. Tobias Blass

    Ian Collins Guest

    On 04/ 9/11 01:38 PM, Ben Bacarisse wrote:
    > Ian Collins<> writes:
    >> On 04/ 9/11 12:18 PM, Keith Thompson wrote:
    >>>
    >>> The code in question is:
    >>>
    >>> /* error.h */
    >>> #ifndef ERROR_H
    >>> #define ERROR_H
    >>>
    >>> const char *errstrs[]={
    >>> "first error",
    >>> "second error",
    >>> ...
    >>> };
    >>> #endif
    >>>
    >>> There won't be one copy per inclusion, because of the header guards,
    >>> but you don't want a *definition* in a header file. If the header
    >>> is included in two or more translation units that are linked into
    >>> a single program, you might get multiple copies of the strings,
    >>> or you might just get a link error. (I'm not quite sure what the
    >>> language permits or requires here, but don't do it.)

    >>
    >> Bugger, I didn't notice there was one to few consts! As you say, one
    >> good reason not to do this!

    >
    > I think you may be confusing C and C++ here. The presence of a "top
    > level" const makes all the difference in C++ (well it did that time I
    > read a C++ reference manual) but it does not make any difference to how
    > the objects may or may not get merged in a C program.


    Um, right again. I think I should confine myself to something
    productive like unclogging more drains this weekend.

    const char* const errstrs[]={
    "first error",
    "second error"
    };

    Will result in one and only one instance of errstrs in C++. I wonder
    why this was never added to C? I can't imagine it breaking any existing
    code.

    --
    Ian Collins
    Ian Collins, Apr 9, 2011
    #7
  8. On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <> wrote:

    > Ian Collins <> writes:
    >> On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >>> Hi,
    >>> I'm currently implementing a string lookup table, mapping error
    >>> numbers to
    >>> human readable strings. So my question is: Can I put the strings in a
    >>> header
    >>> file, or will I end up with N exact copies of this array (N being the
    >>> number
    >>> of inclusions of this file).

    >>
    >> There will only be one copy.

    >
    > The code in question is:
    >
    > /* error.h */
    > #ifndef ERROR_H
    > #define ERROR_H
    >
    > const char *errstrs[]={
    > "first error",
    > "second error",
    > ...
    > };
    > #endif
    >
    > There won't be one copy per inclusion, because of the header guards,
    > but you don't want a *definition* in a header file. If the header
    > is included in two or more translation units that are linked into
    > a single program, you might get multiple copies of the strings,
    > or you might just get a link error. (I'm not quite sure what the
    > language permits or requires here, but don't do it.)
    >
    > Here's what I came up with. Note that it makes errstrs a pointer
    > rather than an array, but you can still refer to errstrs[0],
    > errstrs[1], etc. If you make it an array, it means that client code
    > can figure out how many elements there are, but it also means that
    > you have to specify the length in the declaration and recompile if
    > it changes.
    >
    > Note that identifiers starting with 'E' are reserved, so I changed
    > the include guard macro name.
    >
    > /* error.h */
    > #ifndef H_ERROR
    > #define H_ERROR
    >
    > const char *const *const errstrs;
    >
    > #endif
    >
    > /* error.c */
    > #include "error.h"
    >
    > static const char *const error_strings[] = {
    > "first error",
    > "second error"
    > };
    >
    > const char *const *const errstrs = error_strings;


    This seems overly complex. Is there any good reason not to have

    /* error.c */
    const char *const error_strings[] = { "first error", "second error" };

    /* error.h */
    extern const char *const error_strings[];

    I.e. why not just make error_strings a global array, and expose the
    array name as an extern? Why go to the trouble of declaring a separate
    pointer?

    (Or, as was suggested elsewhere in this thread, make the whole thing
    static, and provide a function to access the members of the array).



    --
    Morris Keesan --
    Morris Keesan, Apr 9, 2011
    #8
  9. "Morris Keesan" <> writes:
    > On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <> wrote:

    [snip]
    > This seems overly complex. Is there any good reason not to have
    >
    > /* error.c */
    > const char *const error_strings[] = { "first error", "second error" };
    >
    > /* error.h */
    > extern const char *const error_strings[];
    >
    > I.e. why not just make error_strings a global array, and expose the
    > array name as an extern? Why go to the trouble of declaring a separate
    > pointer?


    I actually tried that. The problem is that any code that includes
    "error.h" has no way of knowing how big the array is. (More precisely,
    the compiler has no way of knowing this when it's compiling a source
    file that includes "error.h".)

    #include "error.h"
    ....
    printf("error_strings has %d elements\n",
    (int)sizeof error_strings / sizeof error_strings[0]);

    gcc gave me a warning that it was assuming the size of the array is 1.
    Other compilers may behave differently.

    You can avoid that by declaring the size of the array, but then you have
    to recompile whenever you add a new error string.

    > (Or, as was suggested elsewhere in this thread, make the whole thing
    > static, and provide a function to access the members of the array).


    Yes.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Apr 9, 2011
    #9
  10. On Fri, 8 Apr 2011 22:43:12 +0000 (UTC), Tobias Blass
    <> wrote:

    >Hi,
    >I'm currently implementing a string lookup table, mapping error numbers to
    >human readable strings. So my question is: Can I put the strings in a header
    >file, or will I end up with N exact copies of this array (N being the number
    >of inclusions of this file). I use gcc on Linux, so if anyone can tell me that
    >gcc will optimise N-1 copies of the array out I'm happy with that, too.
    >
    >/* error.h */
    >#ifndef ERROR_H
    >#define ERROR_H
    >
    >const char *errstrs[]={
    > "first error",
    > "second error",
    > ...
    > };
    >#endif


    If the header is included at file scope, then per 6.9.2 the
    declaration of errstrs is also an "external definition".

    If the header is included in multiple translation units, errstrs will
    be defined in each object module.

    Paragraph 6.9-5 requires that there be only one such definition.

    Chances are the linker will complain when you attempt to combine all
    the object modules into a single program.

    --
    Remove del for email
    Barry Schwarz, Apr 9, 2011
    #10
  11. Tobias Blass

    Tobias Blass Guest

    On 2011-04-09, Keith Thompson <> wrote:
    > Ian Collins <> writes:
    >> On 04/ 9/11 10:43 AM, Tobias Blass wrote:
    >>> Hi,
    >>> I'm currently implementing a string lookup table, mapping error numbers to
    >>> human readable strings. So my question is: Can I put the strings in a header
    >>> file, or will I end up with N exact copies of this array (N being the number
    >>> of inclusions of this file).

    >>
    >> There will only be one copy.

    >
    > The code in question is:
    >
    > /* error.h */
    > #ifndef ERROR_H
    > #define ERROR_H
    >
    > const char *errstrs[]={
    > "first error",
    > "second error",
    > ...
    > };
    > #endif
    >
    > There won't be one copy per inclusion, because of the header guards,
    > but you don't want a *definition* in a header file. If the header
    > is included in two or more translation units that are linked into
    > a single program, you might get multiple copies of the strings,
    > or you might just get a link error. (I'm not quite sure what the
    > language permits or requires here, but don't do it.)

    That's what I meant by "inclusion". I've got some .c files, each of them
    includes error.h, but I don't want to have 5 Instances of the same table.
    > Note that identifiers starting with 'E' are reserved, so I changed
    > the include guard macro name.

    Thanks for the note, I didn't know that
    > /* error.h */
    > #ifndef H_ERROR
    > #define H_ERROR
    >
    > const char *const *const errstrs;
    >
    > #endif
    >
    > /* error.c */
    > #include "error.h"
    >
    > static const char *const error_strings[] = {
    > "first error",
    > "second error"
    > };
    >
    > const char *const *const errstrs = error_strings;
    >

    I wanted to do that first, but I think it's quite ugly to have a separate C file
    just for the table, so I wanted to ask whether it's possible to do that in the
    header file instead.
    (The const thing is a good hint, I find it rather difficult to remember which
    const has which effect */
    >
    > It might be simpler for error.h to declare a function that takes an int
    > and returns a pointer to the error message.
    >

    That's possibly true, but I think it's easier to change an entry in a table
    than to change it in a function.
    Tobias Blass, Apr 9, 2011
    #11
  12. Tobias Blass

    Tobias Blass Guest

    On 2011-04-09, Keith Thompson <> wrote:
    > "Morris Keesan" <> writes:
    >> On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <> wrote:

    > [snip]
    >> This seems overly complex. Is there any good reason not to have
    >>
    >> /* error.c */
    >> const char *const error_strings[] = { "first error", "second error" };
    >>
    >> /* error.h */
    >> extern const char *const error_strings[];
    >>
    >> I.e. why not just make error_strings a global array, and expose the
    >> array name as an extern? Why go to the trouble of declaring a separate
    >> pointer?

    > I actually tried that. The problem is that any code that includes
    > "error.h" has no way of knowing how big the array is. (More precisely,
    > the compiler has no way of knowing this when it's compiling a source
    > file that includes "error.h".)
    >

    I thought the Compiler can calculate the size of a constant array by itself?
    You can write
    int arr[]={1,2,3,4,5};
    And the Compiler knows arr should have 5 elements, so why is it possible with
    int's but not with pointers?
    (I have to admit that I haven't tested error.h because I just have written this
    array so far when this question came up )
    > #include "error.h"
    > ...
    > printf("error_strings has %d elements\n",
    > (int)sizeof error_strings / sizeof error_strings[0]);
    >
    > gcc gave me a warning that it was assuming the size of the array is 1.
    > Other compilers may behave differently.
    >
    > You can avoid that by declaring the size of the array, but then you have
    > to recompile whenever you add a new error string.
    >
    >> (Or, as was suggested elsewhere in this thread, make the whole thing
    >> static, and provide a function to access the members of the array).

    >
    > Yes.
    >
    Tobias Blass, Apr 9, 2011
    #12
  13. Tobias Blass

    Ian Collins Guest

    On 04/ 9/11 09:36 PM, Tobias Blass wrote:
    > On 2011-04-09, Keith Thompson<> wrote:
    >>
    >> It might be simpler for error.h to declare a function that takes an int
    >> and returns a pointer to the error message.
    >>

    > That's possibly true, but I think it's easier to change an entry in a table
    > than to change it in a function.


    Why?

    It's the no less typing and a lot less rebuilding.

    --
    Ian Collins
    Ian Collins, Apr 9, 2011
    #13
  14. Tobias Blass

    Tobias Blass Guest

    On 2011-04-09, Barry Schwarz <> wrote:
    > On Fri, 8 Apr 2011 22:43:12 +0000 (UTC), Tobias Blass
    ><> wrote:
    >
    >>Hi,
    >>I'm currently implementing a string lookup table, mapping error numbers to
    >>human readable strings. So my question is: Can I put the strings in a header
    >>file, or will I end up with N exact copies of this array (N being the number
    >>of inclusions of this file). I use gcc on Linux, so if anyone can tell me that
    >>gcc will optimise N-1 copies of the array out I'm happy with that, too.
    >>
    >>/* error.h */
    >>#ifndef ERROR_H
    >>#define ERROR_H
    >>
    >>const char *errstrs[]={
    >> "first error",
    >> "second error",
    >> ...
    >> };
    >>#endif

    >
    > If the header is included at file scope, then per 6.9.2 the
    > declaration of errstrs is also an "external definition".
    >
    > If the header is included in multiple translation units, errstrs will
    > be defined in each object module.
    >
    > Paragraph 6.9-5 requires that there be only one such definition.
    >
    > Chances are the linker will complain when you attempt to combine all
    > the object modules into a single program.
    >

    Ok thanks, that answers my question. I'll put it in a .c file and declare it as
    extern
    Tobias Blass, Apr 9, 2011
    #14
  15. Tobias Blass <> writes:

    > On 2011-04-09, Keith Thompson <> wrote:
    >> "Morris Keesan" <> writes:
    >>> On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <> wrote:

    >> [snip]
    >>> This seems overly complex. Is there any good reason not to have
    >>>
    >>> /* error.c */
    >>> const char *const error_strings[] = { "first error", "second error" };
    >>>
    >>> /* error.h */
    >>> extern const char *const error_strings[];
    >>>
    >>> I.e. why not just make error_strings a global array, and expose the
    >>> array name as an extern? Why go to the trouble of declaring a separate
    >>> pointer?

    >> I actually tried that. The problem is that any code that includes
    >> "error.h" has no way of knowing how big the array is. (More precisely,
    >> the compiler has no way of knowing this when it's compiling a source
    >> file that includes "error.h".)
    >>

    > I thought the Compiler can calculate the size of a constant array by itself?
    > You can write
    > int arr[]={1,2,3,4,5};
    > And the Compiler knows arr should have 5 elements, so why is it possible with
    > int's but not with pointers?


    There is no difference between ints and pointers in this regard but the
    problem is not in error.c but the error.h. Translation units that
    include it (other than error.c) will fall fowl of 6.9.2 p2.

    The declaration of error_strings in error.h is a "tentative definition"
    and will cause the translation unit to have a definition of
    error_strings as an array of one element initialised to a null pointer.

    > (I have to admit that I haven't tested error.h because I just have written this
    > array so far when this question came up )
    >> #include "error.h"
    >> ...
    >> printf("error_strings has %d elements\n",
    >> (int)sizeof error_strings / sizeof error_strings[0]);
    >>
    >> gcc gave me a warning that it was assuming the size of the array is 1.
    >> Other compilers may behave differently.


    That's mandated by the standard as far as I can see. Conforming
    implementations can't behave differently.

    <snip>
    --
    Ben.
    Ben Bacarisse, Apr 9, 2011
    #15
  16. Barry Schwarz <> writes:
    <snip>
    > Paragraph 6.9-5 requires that there be only one such definition.


    Thanks for this. I knew it was there but for some strange reason I could
    not find it last night despite much searching (and it's not as if it is
    not exactly where one would expect it to be!).

    <snip>
    --
    Ben.
    Ben Bacarisse, Apr 9, 2011
    #16
  17. On Sat, 09 Apr 2011 00:28:35 -0400, Keith Thompson <> wrote:

    > "Morris Keesan" <> writes:
    >> On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <>
    >> wrote:

    > [snip]
    >> This seems overly complex. Is there any good reason not to have
    >>
    >> /* error.c */
    >> const char *const error_strings[] = { "first error", "second error" };
    >>
    >> /* error.h */
    >> extern const char *const error_strings[];
    >>
    >> I.e. why not just make error_strings a global array, and expose the
    >> array name as an extern? Why go to the trouble of declaring a separate
    >> pointer?

    >
    > I actually tried that. The problem is that any code that includes
    > "error.h" has no way of knowing how big the array is. (More precisely,
    > the compiler has no way of knowing this when it's compiling a source
    > file that includes "error.h".)


    But hiding the array completely, and only exposing a pointer to it, doesn't
    solve that problem.

    > #include "error.h"
    > ...
    > printf("error_strings has %d elements\n",
    > (int)sizeof error_strings / sizeof error_strings[0]);
    >
    > gcc gave me a warning that it was assuming the size of the array is 1.
    > Other compilers may behave differently.
    >
    > You can avoid that by declaring the size of the array, but then you have
    > to recompile whenever you add a new error string.


    I don't understand this last comment. You have to recompile whenever you
    add a new error string, anyway, but you only have to recompile the module
    that has the array definition.

    Or by not needing to know the size of the array.
    const char * const err_strings = {
    "error 1",
    "error 2",
    ...
    "error n",
    NULL
    };

    or
    /* error.c */
    const char * const err_strings = { "err1", "err2", ... "errn" };
    const size_t n_errs = sizeof err_strings/sizeof err_strings[0];

    /* error.h */
    extern const char * const err_strings[];
    extern const size_t n_errs;

    --
    Morris Keesan --
    Morris Keesan, Apr 9, 2011
    #17
  18. On Sat, 09 Apr 2011 05:41:18 -0400, Tobias Blass <>
    wrote:

    > On 2011-04-09, Keith Thompson <> wrote:
    >> "Morris Keesan" <> writes:
    >>> On Fri, 08 Apr 2011 20:18:03 -0400, Keith Thompson <>
    >>> wrote:

    >> [snip]
    >>> This seems overly complex. Is there any good reason not to have
    >>>
    >>> /* error.c */
    >>> const char *const error_strings[] = { "first error", "second error" };
    >>>
    >>> /* error.h */
    >>> extern const char *const error_strings[];
    >>>
    >>> I.e. why not just make error_strings a global array, and expose the
    >>> array name as an extern? Why go to the trouble of declaring a separate
    >>> pointer?

    >> I actually tried that. The problem is that any code that includes
    >> "error.h" has no way of knowing how big the array is. (More precisely,
    >> the compiler has no way of knowing this when it's compiling a source
    >> file that includes "error.h".)
    >>

    > I thought the Compiler can calculate the size of a constant array by
    > itself?
    > You can write
    > int arr[]={1,2,3,4,5};
    > And the Compiler knows arr should have 5 elements, so why is it possible
    > with int's but not with pointers?


    The problem is not because of pointers. In error.c, where you define
    the array with an initializer, the compiler is calculating the size of
    the array. But code that includes "error.h", with just the declaration
    "char *error_strings[]", doesn't have access to that size.

    --
    Morris Keesan --
    Morris Keesan, Apr 9, 2011
    #18
  19. On Sat, 09 Apr 2011 05:36:42 -0400, Tobias Blass <>
    wrote:
    ....
    >> It might be simpler for error.h to declare a function that takes an int
    >> and returns a pointer to the error message.
    >>

    > That's possibly true, but I think it's easier to change an entry in a
    > table than to change it in a function.


    But you can keep your strings in a table and still provide access to them
    only through a function:

    static const char *const error_strings = {
    "error 1",
    "error 2",
    ...
    "error n"
    };

    const char *error_message(unsigned int err_number)
    {
    if (err_number >= (sizeof error_strings / sizeof error_strings[0]))
    return NULL; // error number out of bounds
    else
    return error_strings[err_number];
    }


    --
    Morris Keesan --
    Morris Keesan, Apr 9, 2011
    #19
  20. On Sat, 09 Apr 2011 12:35:13 -0400, I wrote:
    ....
    >
    > Or by not needing to know the size of the array.
    > const char * const err_strings = {


    Oops. I obviously meant to type err_strings[]

    > "error 1",
    > "error 2",
    > ...
    > "error n",
    > NULL
    > };


    But I wasn't thinking clearly enough here. For this sort of application,
    where you just want to index into the array, having a NULL to flag the
    end of the array isn't particularly useful. You really do want to know the
    size of the array, so that you can catch out-of-bounds indexes. But hiding
    the array and providing just an extern pointer to it doesn't address that
    issue. It merely keeps the naive programmer from attempting to find the
    size.
    --
    Morris Keesan --
    Morris Keesan, Apr 9, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Martin Magnusson
    Replies:
    2
    Views:
    503
    John Harrison
    Oct 8, 2004
  2. sinbad
    Replies:
    7
    Views:
    655
    sinbad
    Jun 19, 2008
  3. Philipp
    Replies:
    21
    Views:
    1,126
    Philipp
    Jan 20, 2009
  4. mlt
    Replies:
    2
    Views:
    832
    Jean-Marc Bourguet
    Jan 31, 2009
  5. Fredxx
    Replies:
    3
    Views:
    644
    Martin Thompson
    Jul 15, 2009
Loading...

Share This Page