What's The Best Practice Defining Error Codes in C

Discussion in 'C Programming' started by rammy, Jun 29, 2012.

  1. rammy

    rammy Guest

    Hi,

    I would like to have someone comments on what's the best practice
    defining error codes in C.
    Here's what I think:
    solution A:
    using enum
    pros: type safe. better for debug (some debugger will show the name
    not only the value)
    cons: enum can not be forward declared which makes all error codes
    couples together with the error code type ( enum )

    Solution B:
    using #define
    pros: decouple, error codes could be defined in different .h file
    cons: macro is bad. no type safe

    Solution C:

    typedef struct Error
    {
    int value;

    } Error;

    static Error const ERROR_OUT_OF_SPACE = { 123 };

    pros: type safe. decouple, the error code type is no longer bound with
    all the error definition
    cons: I don't know any one doing it this way so I'm not sure if it has
    some drawbacks or is it bad for (runtime/space) performance.
    If using pure C, user could not compare the error value directly but
    have to compare the inner "value" member which is not convenience.

    Thanks for your help :)
     
    rammy, Jun 29, 2012
    #1
    1. Advertising

  2. rammy

    rammy Guest

    Hello? is this forum be down??
     
    rammy, Jun 29, 2012
    #2
    1. Advertising

  3. rammy <> writes:
    > Hello? is this forum be down??


    You asked your question 36 minutes ago. Be patient.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jun 29, 2012
    #3
  4. rammy

    Stefan Ram Guest

    rammy <> writes:
    >using #define
    >pros: decouple, error codes could be defined in different .h file
    >cons: macro is bad. no type safe


    Most libraries I am aware of, use #define IIRC. So, I'd use that, too.

    But there are more decisions to be made:

    Do you want to have codes be unique per function, per library, or
    globally (as far as code was written under your control)?

    Do you want codes to be structured (so that certain bits have certain
    meanings) or unstructured?

    Heck, sometimes, I just use naked literals: 1, 2, 3, and so ... .
     
    Stefan Ram, Jun 29, 2012
    #4
  5. rammy

    Eric Sosman Guest

    On 6/29/2012 4:29 PM, rammy wrote:
    > Hi,
    >
    > I would like to have someone comments on what's the best practice
    > defining error codes in C.
    > Here's what I think:
    > solution A:
    > using enum
    > pros: type safe. better for debug (some debugger will show the name
    > not only the value)
    > cons: enum can not be forward declared which makes all error codes
    > couples together with the error code type ( enum )


    "Type safe" is too optimistic. An enum is some kind of integer
    type, and integer types are freely interconvertible (as long as the
    values are in range). A named enum value is just an `int' constant,
    and can be stored in any integer variable (of sufficient range).
    Try it yourself:

    enum Fruit { APPLE, BANANA, CHERRY } fruit;
    enum Motor { OTTO, DIESEL, STEAM } motor;
    fruit = OTTO;
    motor = BANANA;
    fruit = PEAR * STEAM;
    motor = sqrt(42.0);
    printf("%g\n", cos(motor));
    ...

    > Solution B:
    > using #define
    > pros: decouple, error codes could be defined in different .h file
    > cons: macro is bad. no type safe


    "Macro is bad" is -- well, that statement is bad.

    > Solution C:
    >
    > typedef struct Error
    > {
    > int value;
    >
    > } Error;
    >
    > static Error const ERROR_OUT_OF_SPACE = { 123 };


    Aside: Are you aware that ERROR_OUT_OF_SPACE is a reserved
    name whenever <errno.h> is included?

    > pros: type safe. decouple, the error code type is no longer bound with
    > all the error definition
    > cons: I don't know any one doing it this way so I'm not sure if it has
    > some drawbacks or is it bad for (runtime/space) performance.
    > If using pure C, user could not compare the error value directly but
    > have to compare the inner "value" member which is not convenience.


    This is type safe, but in a limited way. If the struct
    declaration is visible (as it would have to be to allow access
    to the embedded member), there's nothing to prevent someone
    creating and returning an Error value you've never heard of:

    Error do_something(void) {
    ...
    Error x;
    x.value = rho * sin(theta);
    return x;
    }

    .... could inject an "unauthorized" code into your system. This
    could be either a pro or a con, depending on your point of view.

    You could regain some type safety by declaring the struct as
    an incomplete type in the public header, declaring some instances
    of it, and using pointers to those instances as the error codes:

    // In the header:
    typedef struct Error *Error;
    extern struct Error OUT_OF_SPACE;
    extern struct Error OUT_OF_SIGHT;
    extern struct Error OUT_OF_MIND;
    ...

    // Usage:
    Error do_something(void) {
    ...
    return &OUT_OF_MIND;
    }
    Since `struct Error' is incomplete, no one can create a new
    instance to point at and thereby give rise to unknown codes.
    Of course, even a moderately determined antagonist can still
    cause trouble with a cast:

    Error be_troublesome(void) {
    return (Error)42;
    }

    To the wider question, I don't think there's a "One size fits
    all" solution. Sometimes you need only a success/failure report,
    and this sort of machinery is overkill. Sometimes success and
    failure come in several kinds (non-overlapping, not too many), and
    schemes of the sort you describe may be appropriate. Sometimes you
    need to report several things about a failure or success (not just
    "login failed" but "login failed because authentication server did
    not respond because no connection to authentication server because
    a network cable is unplugged"), and a single-code-per-failure-mode
    approach would suffer combinatorial explosion.

    Instead of seeking a single "best" error-reporting scheme (which
    I doubt exists), I suggest you contemplate the library or other
    facility that you're building, and ask yourself what kinds and amounts
    of status information the callers can make good use of. You're likely
    to come up with different scenarios for different facilities, so pick
    a facility-specific approach -- and implement it well.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 29, 2012
    #5
  6. בת×ריך ×™×•× ×©×™×©×™, 29 ביוני 2012 21:29:33 UTC+1, מ×ת rammy:
    >
    > I would like to have someone comments on what's the best practice
    > defining error codes in C.
    >

    The way I do it is this. I divide the soruce files for the program into four groups: this program only, this platform only. this program only, any platform, this platform only, any program. Any program, any platform.
    So a random number generator would most likely be "any program,any platform". Code to make the spaceship fire when the player presses the spacebar would probably be this platform only, this program only.
    For the last two groups, the "any program" files, you need to pass up errors to the caller. Let's say that someone tries to generate a random number with a range too big for our generator to handle. We might decide that in this case, we'll always return -1. The process is ad hoc, and there shouldn'tbe any dependency. We need to be able to cut and paste our random number generator from the space invaders game, put it into a roulette game or a protein structure predictor, and have it still work.
    For the first two groups, the files will never be used outside of the specific project. So it might be appropriate to have centralised errors with a file "errorcodes.h" somewhere containing a list of human-meaningful enums.
     
    Malcolm McLean, Jun 30, 2012
    #6
  7. rammy

    rammy Guest

    On Fri, 29 Jun 2012 17:25:49 -0400, Eric Sosman wrote:

    > On 6/29/2012 4:29 PM, rammy wrote:
    >> Hi,
    >>
    >> I would like to have someone comments on what's the best practice
    >> defining error codes in C.
    >> Here's what I think:
    >> solution A:
    >> using enum
    >> pros: type safe. better for debug (some debugger will show the name not
    >> only the value)
    >> cons: enum can not be forward declared which makes all error codes
    >> couples together with the error code type ( enum )

    >
    > "Type safe" is too optimistic. An enum is some kind of integer
    > type, and integer types are freely interconvertible (as long as the
    > values are in range). A named enum value is just an `int' constant, and
    > can be stored in any integer variable (of sufficient range). Try it
    > yourself:
    >
    > enum Fruit { APPLE, BANANA, CHERRY } fruit; enum Motor { OTTO,

    DIESEL,
    > STEAM } motor; fruit = OTTO;
    > motor = BANANA;
    > fruit = PEAR * STEAM;
    > motor = sqrt(42.0);
    > printf("%g\n", cos(motor));
    > ...


    Yes and No. As a module We'd like to split the error code to two
    category, those for the client and those inside. We don't want to
    define all the error code in one place which introduce unnecessary
    couple. But for one category, it's better that they are defined in one
    place.

    >> Solution B:
    >> using #define
    >> pros: decouple, error codes could be defined in different .h file cons:
    >> macro is bad. no type safe

    >
    > "Macro is bad" is -- well, that statement is bad.


    So I guess you dislike macro either :)

    >> Solution C:
    >>
    >> typedef struct Error
    >> {
    >> int value;
    >>
    >> } Error;
    >>
    >> static Error const ERROR_OUT_OF_SPACE = { 123 };

    >
    > Aside: Are you aware that ERROR_OUT_OF_SPACE is a reserved
    > name whenever <errno.h> is included?



    Thanks for the reminder. Actually all identifiers are prefixed with
    module name.(how long will namespace be introduced into C)

    >> pros: type safe. decouple, the error code type is no longer bound with
    >> all the error definition
    >> cons: I don't know any one doing it this way so I'm not sure if it has
    >> some drawbacks or is it bad for (runtime/space) performance. If using
    >> pure C, user could not compare the error value directly but have to
    >> compare the inner "value" member which is not convenience.

    >
    > This is type safe, but in a limited way. If the struct
    > declaration is visible (as it would have to be to allow access to the
    > embedded member), there's nothing to prevent someone creating and
    > returning an Error value you've never heard of:
    >
    > Error do_something(void) {
    > ...
    > Error x;
    > x.value = rho * sin(theta);
    > return x;
    > }
    >
    > ... could inject an "unauthorized" code into your system. This could be
    > either a pro or a con, depending on your point of view.
    >
    > You could regain some type safety by declaring the struct as
    > an incomplete type in the public header, declaring some instances of it,
    > and using pointers to those instances as the error codes:
    >
    > // In the header:
    > typedef struct Error *Error;
    > extern struct Error OUT_OF_SPACE;
    > extern struct Error OUT_OF_SIGHT;
    > extern struct Error OUT_OF_MIND;
    > ...
    >
    > // Usage:
    > Error do_something(void) {
    > ...
    > return &OUT_OF_MIND;
    > }
    > Since `struct Error' is incomplete, no one can create a new instance to
    > point at and thereby give rise to unknown codes. Of course, even a
    > moderately determined antagonist can still cause trouble with a cast:
    >
    > Error be_troublesome(void) {
    > return (Error)42;
    > }


    By decouple I mean the possibility to define new error code
    somewhere else. I know it requires discipline to do so. Like I said
    we'd like to separate private error code from public interface.

    > To the wider question, I don't think there's a "One size fits
    > all" solution. Sometimes you need only a success/failure report, and
    > this sort of machinery is overkill. Sometimes success and failure come
    > in several kinds (non-overlapping, not too many), and schemes of the
    > sort you describe may be appropriate. Sometimes you need to report
    > several things about a failure or success (not just "login failed" but
    > "login failed because authentication server did not respond because no
    > connection to authentication server because a network cable is
    > unplugged"), and a single-code-per-failure-mode approach would suffer
    > combinatorial explosion.
    >
    > Instead of seeking a single "best" error-reporting scheme (which
    > I doubt exists), I suggest you contemplate the library or other facility
    > that you're building, and ask yourself what kinds and amounts of status
    > information the callers can make good use of. You're likely to come up
    > with different scenarios for different facilities, so pick a
    > facility-specific approach -- and implement it well.


    I will stick with solution A) for now.

    However, another silly question:

    How about:

    typedef struct ErrorTag* Error;
    static Error const = 123;

    I'm living in C++ world, so I want to try my best to make the API type
    safe. Is there any way except enum could give a type safe error code
    solution ?

    Thanks for your time :)
     
    rammy, Jun 30, 2012
    #7
  8. rammy <> writes:
    <snip>
    > I'm living in C++ world, so I want to try my best to make the API type
    > safe. Is there any way except enum could give a type safe error code
    > solution ?


    What does "living in C++ world" mean? Do you mean you are used to C++'s
    more sophisticated error reporting facilities, or it slightly stronger
    type checking?

    C is not a type-safe language (neither is C++ for that matter) so unless
    you say what you are prepared to compromise on there is no solution at
    all.

    --
    Ben.
     
    Ben Bacarisse, Jun 30, 2012
    #8
  9. rammy

    Ian Collins Guest

    On 07/ 1/12 08:57 AM, rammy wrote:

    <snip>

    > By decouple I mean the possibility to define new error code
    > somewhere else. I know it requires discipline to do so. Like I said
    > we'd like to separate private error code from public interface.


    A couple of projects I have worked on solved this by defining the error
    codes in something other than C and generating the C header files from
    there. So each set got its own header, but the overall definitions were
    elsewhere. This had the bonus advantage of providing the "extensible
    enum" support C lacks.

    > I'm living in C++ world, so I want to try my best to make the API type
    > safe. Is there any way except enum could give a type safe error code
    > solution ?


    You will have to accept that from a C++ programmer's perspective, enums
    in C are somewhat broken due to automatic conversions. While C++ rules
    prevent silly mistakes like

    typedef enum { Good, Bad } Result;

    Result oops() { return -1; }

    C unfortunately does not. So from a type safety perspective, enums are
    no better than #defines.

    --
    Ian Collins
     
    Ian Collins, Jun 30, 2012
    #9
  10. rammy

    Eric Sosman Guest

    On 6/30/2012 4:57 PM, rammy wrote:
    > On Fri, 29 Jun 2012 17:25:49 -0400, Eric Sosman wrote:
    >
    >> On 6/29/2012 4:29 PM, rammy wrote:
    >>> Hi,
    >>>
    >>> I would like to have someone comments on what's the best practice
    >>> defining error codes in C.
    >>> Here's what I think:
    >>> solution A:
    >>> using enum
    >>> pros: type safe. better for debug (some debugger will show the name not
    >>> only the value)
    >>> cons: enum can not be forward declared which makes all error codes
    >>> couples together with the error code type ( enum )

    >>
    >> "Type safe" is too optimistic. An enum is some kind of integer
    >> type, and integer types are freely interconvertible (as long as the
    >> values are in range). A named enum value is just an `int' constant, and
    >> can be stored in any integer variable (of sufficient range). Try it
    >> yourself:
    >>
    >> enum Fruit { APPLE, BANANA, CHERRY } fruit; enum Motor { OTTO,

    > DIESEL,
    >> STEAM } motor; fruit = OTTO;
    >> motor = BANANA;
    >> fruit = PEAR * STEAM;
    >> motor = sqrt(42.0);
    >> printf("%g\n", cos(motor));
    >> ...

    >
    > Yes and No. As a module We'd like to split the error code to two
    > category, those for the client and those inside. We don't want to
    > define all the error code in one place which introduce unnecessary
    > couple. But for one category, it's better that they are defined in one
    > place.


    Perhaps my typo caused you to miss the point :-( What I mean
    is that an enum is not "type safe" as you seem to think. C will
    not prevent you from setting an `enum X' variable to an `enum Y'
    value, nor to `42', nor to the result of some arbitrary expression.

    enum X { A, B, C } foobar(void);
    switch (foobar()) {
    case A: ... break;
    case B: ... break;
    case C: ... break;
    default: ... // Yes, this case *can* occur.
    }

    >>> Solution B:
    >>> using #define
    >>> pros: decouple, error codes could be defined in different .h file cons:
    >>> macro is bad. no type safe

    >>
    >> "Macro is bad" is -- well, that statement is bad.

    >
    > So I guess you dislike macro either :)


    Macros are a part of the C language. They are sometimes useful,
    sometimes dangerous -- like most of the rest of C. The blanket
    statement "macro is bad" is nonsense.

    >>> Solution C:
    >>>
    >>> typedef struct Error
    >>> {
    >>> int value;
    >>>
    >>> } Error;
    >>>
    >>> static Error const ERROR_OUT_OF_SPACE = { 123 };

    >>
    >> Aside: Are you aware that ERROR_OUT_OF_SPACE is a reserved
    >> name whenever <errno.h> is included?

    >
    > Thanks for the reminder. Actually all identifiers are prefixed with
    > module name.(how long will namespace be introduced into C)


    Probably never, although no deity has granted me the gift of
    prophecy and I could be mistaken. If namespaces ever *are* added
    to C, their use will be "mostly optional" in the name of backwards
    compatibility: The investment in existing non-namespace C code is
    enormous, and cannot simply be abandoned.

    > [...]
    > By decouple I mean the possibility to define new error code
    > somewhere else. I know it requires discipline to do so. Like I said
    > we'd like to separate private error code from public interface.


    Extensible error codes (extensible codes of any kind) require
    discipline from both the producer and the consumer. For example,
    if a caller uses foobar() and checks for SUCCESS or OUT_OF_SPACE,
    a future foobar() version that starts reporting QUOTA_EXCEEDED as
    well may break the caller. Silently. So: "Be careful out there."

    > However, another silly question:
    >
    > How about:
    >
    > typedef struct ErrorTag* Error;
    > static Error const = 123;


    The compiler is required to issue a diagnostic, for at least
    two reasons: First, the second line looks like a declaration but
    declares no identifier. Second, the constant `123' cannot be
    converted automatically to any kind of pointer. I cannot tell
    what you intended to write, so I can't comment on "How about."

    > I'm living in C++ world, [...]


    Then you're in the wrong newsgroup. comp.lang.c++ is just
    down the hall to your right, past the broom closet.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jun 30, 2012
    #10
  11. Eric Sosman <> writes:
    > On 6/30/2012 4:57 PM, rammy wrote:

    [...]
    >> I'm living in C++ world, [...]

    >
    > Then you're in the wrong newsgroup. comp.lang.c++ is just
    > down the hall to your right, past the broom closet.


    I thought it was past the water cooler.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Jul 1, 2012
    #11
  12. rammy

    Eric Sosman Guest

    On 6/30/2012 7:12 PM, Keith Thompson wrote:
    > Eric Sosman <> writes:
    >> On 6/30/2012 4:57 PM, rammy wrote:

    > [...]
    >>> I'm living in C++ world, [...]

    >>
    >> Then you're in the wrong newsgroup. comp.lang.c++ is just
    >> down the hall to your right, past the broom closet.

    >
    > I thought it was past the water cooler.


    You're right. Gosh, that thing sure needs fixing-up!
    Ah, but that's C++ for you: All structure, no maintenance.

    --
    Eric Sosman
    d
     
    Eric Sosman, Jul 1, 2012
    #12
  13. rammy

    Maxim Fomin Guest

    воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 1:34:07 UTC+4 пользователь Ian Collins напиÑал:
    > On 07/ 1/12 08:57 AM, rammy wrote:
    >
    > <snip>
    >
    > > I'm living in C++ world, so I want to try my best to make the API type
    > > safe. Is there any way except enum could give a type safe error code
    > > solution ?

    >
    > You will have to accept that from a C++ programmer's perspective, enums
    > in C are somewhat broken due to automatic conversions. While C++ rules
    > prevent silly mistakes like
    >
    > typedef enum { Good, Bad } Result;
    >
    > Result oops() { return -1; }
    >
    > C unfortunately does not. So from a type safety perspective, enums are
    > no better than #defines.
    >
    > --
    > Ian Collins


    From what and to what are enumerations in C converted?
     
    Maxim Fomin, Jul 1, 2012
    #13
  14. rammy

    Ian Collins Guest

    On 07/ 1/12 05:39 PM, Maxim Fomin wrote:
    > воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 1:34:07 UTC+4 пользователь Ian Collins напиÑал:
    >> On 07/ 1/12 08:57 AM, rammy wrote:
    >>
    >> <snip>
    >>
    >>> I'm living in C++ world, so I want to try my best to make the API type
    >>> safe. Is there any way except enum could give a type safe error code
    >>> solution ?

    >>
    >> You will have to accept that from a C++ programmer's perspective, enums
    >> in C are somewhat broken due to automatic conversions. While C++ rules
    >> prevent silly mistakes like
    >>
    >> typedef enum { Good, Bad } Result;
    >>
    >> Result oops() { return -1; }
    >>
    >> C unfortunately does not. So from a type safety perspective, enums are
    >> no better than #defines.

    >
    > From what and to what are enumerations in C converted?


    Anything that can be converted to or from an int, which includes other
    enums.

    --
    Ian Collins
     
    Ian Collins, Jul 1, 2012
    #14
  15. rammy

    Maxim Fomin Guest

    воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 11:05:22 UTC+4 пользователь Ian Collins напиÑал:
    > On 07/ 1/12 05:39 PM, Maxim Fomin wrote:
    > > воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 1:34:07 UTC+4 пользователь Ian Collins напиÑал:
    > >> On 07/ 1/12 08:57 AM, rammy wrote:
    > >>
    > >> <snip>
    > >>
    > >>> I'm living in C++ world, so I want to try my best to make the API type
    > >>> safe. Is there any way except enum could give a type safe error code
    > >>> solution ?
    > >>
    > >> You will have to accept that from a C++ programmer's perspective, enums
    > >> in C are somewhat broken due to automatic conversions. While C++ rules
    > >> prevent silly mistakes like
    > >>
    > >> typedef enum { Good, Bad } Result;
    > >>
    > >> Result oops() { return -1; }
    > >>
    > >> C unfortunately does not. So from a type safety perspective, enums are
    > >> no better than #defines.

    > >
    > > From what and to what are enumerations in C converted?

    >
    > Anything that can be converted to or from an int, which includes other
    > enums.
    >
    > --
    > Ian Collins


    AFAIK enumeration constants are of type int, so they are not converted to int. Example above is closely equivalent (but not 100%) to:

    #define Good 0
    #define Bad 1
    typedef ???? Result
    .....
    Result oops() { return -1; }
    where ???? is for char, int or unsigned int
    It is obvious that -1 may or may be not within intended return range. However, nothing stops from:
    int oops(); // should return only withing [100; 1000]
    ....
    if (some error)
    return -1; // forgot about spec
    ....

    Theoretically problem may occur when ???? is char and oops() returns value out of char range or ???? is unsigned int an negative value is returned. Inboth cases compiler would issue warning about implicit conversions.

    IMHO the problem is not that C enum is "type unsafe" but is in applying identical assumptions to different things.
     
    Maxim Fomin, Jul 1, 2012
    #15
  16. Maxim Fomin <> writes:

    > воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 11:05:22 UTC+4 пользователь Ian Collins напиÑал:
    >> On 07/ 1/12 05:39 PM, Maxim Fomin wrote:
    >> > воÑкреÑенье, 1 Ð¸ÑŽÐ»Ñ 2012 г., 1:34:07 UTC+4 пользователь Ian Collins напиÑал:
    >> >> On 07/ 1/12 08:57 AM, rammy wrote:
    >> >>
    >> >> <snip>
    >> >>
    >> >>> I'm living in C++ world, so I want to try my best to make the API type
    >> >>> safe. Is there any way except enum could give a type safe error code
    >> >>> solution ?
    >> >>
    >> >> You will have to accept that from a C++ programmer's perspective, enums
    >> >> in C are somewhat broken due to automatic conversions. While C++ rules
    >> >> prevent silly mistakes like
    >> >>
    >> >> typedef enum { Good, Bad } Result;
    >> >>
    >> >> Result oops() { return -1; }
    >> >>
    >> >> C unfortunately does not. So from a type safety perspective, enums are
    >> >> no better than #defines.
    >> >
    >> > From what and to what are enumerations in C converted?

    >>
    >> Anything that can be converted to or from an int, which includes other
    >> enums.

    <snip sig>

    > AFAIK enumeration constants are of type int, so they are not converted
    > to int.


    Agreed, but your question was about enumerations and not just their
    constants so you need to consider what happens to the values of enum
    objects as well as to enum constants.

    > Example above is closely equivalent (but not 100%) to:
    >
    > #define Good 0
    > #define Bad 1
    > typedef ???? Result
    > ....
    > Result oops() { return -1; }
    > where ???? is for char, int or unsigned int
    > It is obvious that -1 may or may be not within intended return range.


    Absolutely (though the type ???? could be any signed or unsigned integer
    type). It is even possible to get an integer overflow: had the return
    been "return 999;" on a system where the compiler chose an 8-bit signed
    char for the enum.

    > However, nothing stops from:
    > int oops(); // should return only withing [100; 1000]
    > ...
    > if (some error)
    > return -1; // forgot about spec
    > ...


    Showing something else that C can't express is not a very strong
    argument for C's enums being how they are! But maybe you were just
    saying that the enum behaviour fits with the fact that C does not have
    range types.

    > Theoretically problem may occur when ???? is char and oops() returns
    > value out of char range or ???? is unsigned int an negative value is
    > returned. In both cases compiler would issue warning about implicit
    > conversions.


    Well it might, but it doesn't have to. I don't think gcc does, though
    there may be an option I'm missing that makes it warn about such things.

    > IMHO the problem is not that C enum is "type unsafe" but is in
    > applying identical assumptions to different things.


    I don't know what you mean here. C's enums present the programmer with
    a number of things to wary of; one of the biggest being that an enum
    type is simply a new type compatible with some unknown integer type.
    That's not always what people expect so, like so much of C, you really
    have to know it not to get tripped up.

    --
    Ben.
     
    Ben Bacarisse, Jul 1, 2012
    #16
  17. rammy

    Tim Rentsch Guest

    Ben Bacarisse <> writes:

    > Maxim Fomin <> writes:
    > [snip]
    >
    >> Example above is closely equivalent (but not 100%) to:
    >>
    >> #define Good 0
    >> #define Bad 1
    >> typedef ???? Result
    >> ....
    >> Result oops() { return -1; }
    >> where ???? is for char, int or unsigned int
    >> It is obvious that -1 may or may be not within intended return range.

    >
    > Absolutely (though the type ???? could be any signed or unsigned integer
    > type). It is even possible to get an integer overflow: had the return
    > been "return 999;" on a system where the compiler chose an 8-bit signed
    > char for the enum. [snip unrelated]


    Strictly speaking that isn't an overflow, but an
    (integer) out-of-range conversion.
     
    Tim Rentsch, Jul 2, 2012
    #17
    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. johny smith
    Replies:
    8
    Views:
    421
    Peter Koch Larsen
    Jul 2, 2004
  2. Replies:
    2
    Views:
    2,845
    Malcolm
    Aug 20, 2005
  3. ׿ǿ Zhuo, Qiang

    What's The Best Practice Defining Error Codes in C

    ׿ǿ Zhuo, Qiang, Nov 16, 2008, in forum: C Programming
    Replies:
    2
    Views:
    1,763
    Zhuo, Qiang ׿ǿ
    Nov 17, 2008
  4. Sergi Pasoev
    Replies:
    0
    Views:
    375
    Sergi Pasoev
    Jun 29, 2012
  5. Justin C
    Replies:
    1
    Views:
    141
    ccc31807
    Nov 11, 2013
Loading...

Share This Page