Mechanism to generate annotated "error codes"

Discussion in 'C Programming' started by Don Y, Mar 1, 2012.

  1. Don Y

    Don Y Guest

    Hi,

    [Please take the time to understand what I'm looking for before
    replying. I've spent a lot of time describing it; it would
    be courteous for you to make a similar investment before
    commenting on it.]

    I have a suite of projects that utilize a common approach to
    error reporting. Instead of a PASS/FAIL result, most functions
    return information regarding the nature of the "failure" (which
    can also include "partial failures"... "warnings"). These
    reports allow upper levels of the application to convey those
    details to the user without exposing all of the *mechanism*
    involved to those upper levels.

    E.g., the application may need a numeric value from the user
    with a particular set of constraints (must be positive, less
    than 293, no more than two decimals, etc.). Of course, it would
    be silly for the upper levels of the application to process
    individual characters to assemble such a "value" and enforce
    those constraints.

    Instead, you'd wrap the behavior in a function that you could
    reuse wherever similar needs arise. That function would be
    parameterized to allow the caller to specify the constraints
    that need to be applied. It would return the value retrieved
    from the user or an indication of problems encountered in
    the parsing of that value -- constraint violations.

    [Note that "from the user" could just as easily be "from a
    file"... i.e., how the error is ultimately reported/handled
    is something that the upper level routines should decide,
    not this lower level function]

    For example, the lower level routine might report:
    - invalid character encountered
    - value below minimum allowed
    - value exceeds maximum allowed
    - too many significant digits

    The "invalid character" report might be embelished:
    - only one decimal point allowed
    - only one *sign* allowed
    - non-digit encountered

    Etc. The information conveyed by each of these allows the
    application to inform the user of the exact nature of the
    "problem" -- instead of just resorting to a "bad value"
    report.

    Each possible "report" needs a mechanism through which the
    caller can ascertain the nature of the error. You *could*
    impose a convention that causes reports to be more easily
    summarized: e.g., 0 for SUCCESS, <0 for errors, >0 for
    warnings (so, if you don't care about warnings the caller
    would test for any "not negative" result codes as being
    "acceptable" -- as in the case of SUCCESS or "too many
    significant digits").

    Of course, there's nothing difficult or magical about this.
    Create an enumeration or a set of manifest constants to
    symbolically represent each of the "results", package them
    in a header file and you're all set!

    That approach is fine for "small" functions with a limited
    number of potential "results". But, consider how you would
    scale it to more comprehensive functions. E.g., the complete
    UI. Managing these "enumerations" gets to be tedious and
    error prone. "Which *values* have been assigned? What is
    a good value to pick for this new 'condition'? etc."

    One approach to ensuring unique "values" for each of these
    "results" is to synthesize them from the function/file name
    and line number where they are detected (instantiating a
    macro at that particular point). This ensures that values
    are unique while hiding the *actual* value from the developer
    (*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
    to 0x27 or 0x7732!).

    The problem then becomes one of making that information available
    to other *consumers*! I.e., wrapping it in a header file that
    others can reference.

    [Note this opens the door for a bootstrap problem but I am
    willing to live with that -- "I'll deal with it later..."]

    A "solution" also needs to address the problem of *explaining*
    the "result" (to the ultimate user). The point at which the
    result is "signaled" contains the most information about the
    nature of the "problem" being reported though it is in a
    very narrowly defined context: i.e., you can tell the user
    "Multiple decimal points encountered" -- though you can't
    indicate the role that the value being entered plays in the
    application (is this a person's wages? the weight of a
    newborn child? the average lifespan of a male tortoise?).

    So, the developer should be able to tie the explanation/commentary
    *to* the (symbolic) result code where the result code is defined
    instead of having to do so "somewhere else" -- hoping to keep the
    explanations in sync with the symbolic names, etc.

    A code fragment with such a system might look like:

    if (*ptr == '.') {
    if (decimalPointEncountered == TRUE) {

    MakeErrorCode(Err_TooManyDecimalPoints,
    "Multiple decimal points encountered.",
    "Only a single decimal point is allowed in numeric
    values."
    )

    result = Err_TooManyDecimalPoints;
    } else {
    decimalPointEncountered = TRUE;
    }
    }
    ...
    return (result);

    Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
    value, here (e.g., __FILE__ ## __LINE__). A script could parse the
    output of the preprocessor extracting all lines of the form
    "#define Err_" to build a suitable header file. And, another
    script could extract the short and long textual explanations of
    the error itself.

    I currently do this with a mix of ad hoc measures. As such,
    it is very fragile (and an annoying drain on my time!). I'm
    hoping for suggestions that might lead me to a better/different
    approach (WITH THE SAME GOALS). Pointers to tools better suited
    to this. *Or*, examples of similar approaches!!

    Thx,
    --don
     
    Don Y, Mar 1, 2012
    #1
    1. Advertising

  2. Don Y

    Willem Guest

    Don Y wrote:
    ) A code fragment with such a system might look like:
    )
    ) if (*ptr == '.') {
    ) if (decimalPointEncountered == TRUE) {
    )
    ) MakeErrorCode(Err_TooManyDecimalPoints,
    ) "Multiple decimal points encountered.",
    ) "Only a single decimal point is allowed in numeric
    ) values."
    ) )
    )
    ) result = Err_TooManyDecimalPoints;
    ) } else {
    ) decimalPointEncountered = TRUE;
    ) }
    ) }
    ) ...
    ) return (result);
    )
    ) Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
    ) value, here (e.g., __FILE__ ## __LINE__). A script could parse the
    ) output of the preprocessor extracting all lines of the form
    ) "#define Err_" to build a suitable header file. And, another
    ) script could extract the short and long textual explanations of
    ) the error itself.
    )
    ) I currently do this with a mix of ad hoc measures. As such,
    ) it is very fragile (and an annoying drain on my time!). I'm
    ) hoping for suggestions that might lead me to a better/different
    ) approach (WITH THE SAME GOALS). Pointers to tools better suited
    ) to this. *Or*, examples of similar approaches!!

    Have you considered using (pointers to constant) strings?

    Like this:

    char *result = 0; /* or: char *result = ""; */
    if (*ptr == '.') {
    if (decimalPointEncountered) {
    result = Err("E:Multiple decimal points encountered:"
    "Only a single decimal point is allowed in numeric values");
    } else {
    decimalPointEncountered = TRUE;
    }
    }
    ...
    return (result);

    You can probably use the __FILE__ and __LINE__ macros to add something
    extra to the string, to make it unique (if that is needed).

    With the first character, you distinguish errors and warnings, and you have
    all the necessary info at your fingertips when you encounter the error.

    It wasn't in your requirements, but if you need your program to check
    against specific errors (EG catch them), I'm sure there's a way to get
    the pointer values of all the error codes into a .h file or something.

    This way, you're still passing around 'magic values', but the required
    info is directly accessible from the value. Downside is that you need
    an indirection to distinguish the error/warning, upside is that you can
    now distinguish more than that if you want.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Mar 1, 2012
    #2
    1. Advertising

  3. Don Y

    Shao Miller Guest

    On 3/1/2012 14:48, Don Y wrote:
    > Hi,
    >
    > [Please take the time to understand what I'm looking for before
    > replying. I've spent a lot of time describing it; it would
    > be courteous for you to make a similar investment before
    > commenting on it.]
    >


    I read the whole thing.

    > I have a suite of projects that utilize a common approach to
    > error reporting. Instead of a PASS/FAIL result, most functions
    > return information regarding the nature of the "failure" (which
    > can also include "partial failures"... "warnings"). These
    > reports allow upper levels of the application to convey those
    > details to the user without exposing all of the *mechanism*
    > involved to those upper levels.
    >
    > [...and more...]


    You might take a look at iPXE's error system. If I recall correctly,
    there's a range of bits for the error type, a range of bits for the
    module (translation unit), and maybe another range or two I'm forgetting
    about (maybe major and minor codes). The special gift that iPXE's
    primary author grants is the ability to look up the error codes on a
    web-page. :)

    If you are going to go with a strategy such as "warnings are positive"
    and "errors are negative" and "success is 0," consider wrapping those
    predicates with macros:

    if (WARNING(result = operation(arg1, arg2))) { /* ... */ } /* or */
    if (SUCCESS(result = operation(arg1, arg2))) { /* ... */ } /* or */
    if (ERROR(result = operation(arg1, arg2))) { /* ... */ } /* etc. */

    then the representation of 'result' needn't be considered and becomes an
    implementation detail.

    > That approach is fine for "small" functions with a limited
    > number of potential "results". But, consider how you would
    > scale it to more comprehensive functions. E.g., the complete
    > UI. Managing these "enumerations" gets to be tedious and
    > error prone. "Which *values* have been assigned? What is
    > a good value to pick for this new 'condition'? etc."


    If you have a single project, I'm not sure why you'd worry about "which
    values have been assigned," since if you use macro/enum identifiers, you
    can change these arbitrarily and recompile. "The last error number I
    made up was 7. I need a new one. I guess I'll make it 8. No wait,
    this one should come before the last one as it's alphabetically lower;
    no problem."

    If you're producing a library, then yeah, I don't think you'd wish to
    change the header in an incompatible fashion in future revisions, as the
    calling programs would break.

    > One approach to ensuring unique "values" for each of these
    > "results" is to synthesize them from the function/file name
    > and line number where they are detected (instantiating a
    > macro at that particular point). This ensures that values
    > are unique while hiding the *actual* value from the developer
    > (*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
    > to 0x27 or 0x7732!).
    >
    > The problem then becomes one of making that information available
    > to other *consumers*! I.e., wrapping it in a header file that
    > others can reference.


    That is something that functions happen to be particularly good at. A
    header can declare a function:

    int ErrHasTooManyDecimalPoints(errtype_t test);

    and the caller need know nothing about the representation of 'errtype_t'
    nor even the range of values... The predicate is what's important, and
    it's identified symbolically, in this case.

    Or if you want the error implementation to be opaque to the lower-level
    functions, you could have:

    int ErrHasTooManyDecimalPoints(errtype_t * errobj, int get_or_set);


    The lower functions can include:

    /* ...function body... */
    ErrHasTooManyDecimalPoints(&result, 1 /* set */ );

    and the caller could:

    /* ...function body... */
    result = operation(arg1, arg2);
    if (ErrHasTooManyDecimalPoints(&result, 0 /* get */ )) {
    /* We know that one. Handle */
    /* ... */
    }

    But of course this seems a fair bit of extra work just to make the error
    system opaque and symbolically accessible.

    > [Note this opens the door for a bootstrap problem but I am
    > willing to live with that -- "I'll deal with it later..."]
    >
    > A "solution" also needs to address the problem of *explaining*
    > the "result" (to the ultimate user). The point at which the
    > result is "signaled" contains the most information about the
    > nature of the "problem" being reported though it is in a
    > very narrowly defined context: i.e., you can tell the user
    > "Multiple decimal points encountered" -- though you can't
    > indicate the role that the value being entered plays in the
    > application (is this a person's wages? the weight of a
    > newborn child? the average lifespan of a male tortoise?).
    >
    > So, the developer should be able to tie the explanation/commentary
    > *to* the (symbolic) result code where the result code is defined
    > instead of having to do so "somewhere else" -- hoping to keep the
    > explanations in sync with the symbolic names, etc.


    An approach to error reporting that I see quite often is very simply:

    int operation(param1, param2);

    If you can't pack all of the information you wish to have associated
    with an exception or error condition or whatever into an 'int', then
    perhaps you're better off allocating some status and passing it around:

    /* my.h */
    /* A simple error code */
    typedef int myerr_t;

    /* Extended status information */
    typedef struct s_status s_status;

    struct s_status {
    const char * message;
    /* ... */
    };

    /* my.c */
    myerr_t operation_foo(
    int * param1,
    char * param2,
    somes_status * status
    ) {
    myerr_t result;
    s_status status_internal;

    /*
    * If the caller hasn't provided storage for status,
    * then they're not interested. Use our own for
    * called functions
    */
    if (!status) {
    status = &status_internal;
    memset(status, 0, sizeof *status);
    }
    /* ... */
    result = operation_bar(13, param2, status);
    if (!MYERR_SUCCESS(result)) {
    /* Actually, we have specific info for this case */
    SetStatusMessage(status, "Bar failed while blargling");
    SetStatusSourcePoint(status, __FILE__, __LINE__);
    /* Twiddle the case for out-of-range major error type */
    if (MYERR_TEST(result, MyErrOutOfRange))
    SetStatusTwiddle(status);
    goto err_bar;
    }

    /* Success! */
    result = SetStatusGeneralSuccess(status);

    err_bar:

    return result;
    }

    > [...and more...]


    However, it's possible that you've already considered and dismissed
    material akin to this response post's content. :)
     
    Shao Miller, Mar 1, 2012
    #3
  4. Don Y

    Don Y Guest

    Hi Willem,

    On 3/1/2012 2:29 PM, Willem wrote:
    > Don Y wrote:
    > ) A code fragment with such a system might look like:
    > )
    > ) if (*ptr == '.') {
    > ) if (decimalPointEncountered == TRUE) {
    > )
    > ) MakeErrorCode(Err_TooManyDecimalPoints,
    > ) "Multiple decimal points encountered.",
    > ) "Only a single decimal point is allowed in numeric
    > ) values."
    > ) )
    > )
    > ) result = Err_TooManyDecimalPoints;
    > ) } else {
    > ) decimalPointEncountered = TRUE;
    > ) }
    > ) }
    > ) ...
    > ) return (result);
    > )
    > ) Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
    > ) value, here (e.g., __FILE__ ## __LINE__). A script could parse the
    > ) output of the preprocessor extracting all lines of the form
    > ) "#define Err_" to build a suitable header file. And, another
    > ) script could extract the short and long textual explanations of
    > ) the error itself.
    > )
    > ) I currently do this with a mix of ad hoc measures. As such,
    > ) it is very fragile (and an annoying drain on my time!). I'm
    > ) hoping for suggestions that might lead me to a better/different
    > ) approach (WITH THE SAME GOALS). Pointers to tools better suited
    > ) to this. *Or*, examples of similar approaches!!
    >
    > Have you considered using (pointers to constant) strings?


    Yes. My first implementation allowed the called function to
    return a pointer to a string (that the caller could embellish
    to communicate with the user).

    Then, the problem of differentiating "warning" explanations from
    "error" explanations arose (I returned only the char* vs. NULL
    for SUCCESS).

    And, it didn't let me extract the text of the explanation from
    the module in which it was "implemented" -- hence the move to
    a separate process step to extract this information from the
    source files.

    > Like this:
    >
    > char *result = 0; /* or: char *result = ""; */
    > if (*ptr == '.') {
    > if (decimalPointEncountered) {
    > result = Err("E:Multiple decimal points encountered:"
    > "Only a single decimal point is allowed in numeric values");
    > } else {
    > decimalPointEncountered = TRUE;
    > }
    > }
    > ...
    > return (result);
    >
    > You can probably use the __FILE__ and __LINE__ macros to add something
    > extra to the string, to make it unique (if that is needed).


    I am currently relying on FILE/LINE to generate a *unique* marker
    for each error "source". For (*contrived*) example:

    if (*ptr == '+') {
    if (signEncountered == TRUE) {
    MakeErrorCode(Err_TooManySignsPos,
    "Multiple signs encountered.",
    "At most, a single sign can preface a numeric
    value."
    )

    result = Err_TooManySignsPos;
    }
    } else if (*ptr == '-') {
    MakeErrorCode(Err_TooManySignsNeg,
    "Multiple signs encountered.",
    "At most, a single sign can preface a numeric
    value."
    )
    result = Err_TooManySignsNeg;
    }
    }

    [Sorry, it was really a lousy example!]

    All I want from the *code* is an indication of where in the code
    a test "failed". The caller can use the error code in a given
    "context" to lookup the error message along with potential
    remedial actions in a database that maps error codes to explanations
    and other documentation in an on-line manual.

    What I need is a good "hook" to let the developer indicate points
    where tests can "fail" (i.e., yield results that seem to be
    contrary to what we HOPE the user was intending).

    [Note that I haven't even discussed I18N/L10N]

    By maintaining the isolation of individual "conditional" failures
    (e.g., instead of lumping both of the above into "Err_TooManySigns"),
    more information can be provided to allow diagnosing any problems
    that the user encounters.

    For example, Err_TooManySignsNeg being signaled ALWAYS (or, whenever
    this particular branch of code happens to be executed) could cause
    you to examine the:
    } else if (*ptr == '-') {
    statement. Perhaps it was really written as:
    } else if (*ptr = '-') {

    If you allow multiple "condition failures" (sorry, this is a lousy
    phrase) to map to the same error, then you have to know where
    *every* case of that error is signaled and explore each path
    individually. E.g., "Err_BadValue" could be signaled anywhere
    *anything* wrong is detected in the value being provided.

    > With the first character, you distinguish errors and warnings, and you have
    > all the necessary info at your fingertips when you encounter the error.
    >
    > It wasn't in your requirements, but if you need your program to check
    > against specific errors (EG catch them), I'm sure there's a way to get
    > the pointer values of all the error codes into a .h file or something.
    >
    > This way, you're still passing around 'magic values', but the required
    > info is directly accessible from the value. Downside is that you need
    > an indirection to distinguish the error/warning, upside is that you can
    > now distinguish more than that if you want.
     
    Don Y, Mar 1, 2012
    #4
  5. Don Y

    Stefan Ram Guest

    Don Y <> writes:
    >Managing these "enumerations" gets to be tedious and error
    >prone.
    >Which *values* have been assigned?


    That's easy. Just keep a single table with two rows:
    number and meaning. There, you can always find the
    answer to this question. (You can use the include
    file with the define-directives.)

    >What is a good value to pick for this new 'condition'?


    The next consecutive number, like: 1, 2, 3, ...

    >etc.


    Feel free to ask more questions!

    >The problem then becomes one of making that information available
    >to other *consumers*! I.e., wrapping it in a header file that
    >others can reference.


    Where's the problem? You create a header file and put
    the definitions in it:

    #define ERROR_NO_MORE_MEMORY_AVAILABLE 1
    #define ERROR_CANT_OPEN_AT_LEAST_ONE_FILE_FOR_READ_ACCESS 2
    ....
    #define ERROR_AT_LEAST_ONE_CLIENT_SUPPLIED_NUMERIC_VALIDITY_CONDITION_IS_NOT_FULFILLED 2351

    >A "solution" also needs to address the problem of *explaining*
    >the "result" (to the ultimate user).


    That's a separate problem of the application author.

    >very narrowly defined context: i.e., you can tell the user
    >"Multiple decimal points encountered" -- though you can't
    >indicate the role that the value being entered plays in the
    >application (is this a person's wages? the weight of a
    >newborn child? the average lifespan of a male tortoise?).


    This is known to the author of the application.

    >I currently do this with a mix of ad hoc measures.


    I use numeric values with meanings relative to a function
    and transform them when passing them upward to the next
    caller.

    For example,

    int filemove( LPTSTR const target, LPTSTR const source )
    { BOOL const success = MoveFile( source, target );
    int const terminate = success ? 1 : filecall_error();
    return terminate; }

    »MoveFile« returns »success« to describe its success,
    the semantics of which are being described in the
    »MoveFile« documentation.

    »filemove« uses an int value with semantics being
    described in the »filemove« documentation. This int
    value is being determined based on the result of two
    other functions called in »filemove«: »MoveFile«
    and »filecall_error«.

    There are no global semantics for result codes in
    this case.

    For a slightly larger example, see list0.c and list1.c in

    http://www.purl.org/stefan_ram/pub/listenverarbeitung_in_c
     
    Stefan Ram, Mar 1, 2012
    #5
  6. Don Y

    Stefan Ram Guest

    Supersedes: <-berlin.de>
    [removed "list0.c" with Supersedes]

    Don Y <> writes:
    >Managing these "enumerations" gets to be tedious and error
    >prone.
    >Which *values* have been assigned?


    That's easy. Just keep a single table with two rows:
    number and meaning. There, you can always find the
    answer to this question. (You can use the include
    file with the define-directives.)

    >What is a good value to pick for this new 'condition'?


    The next consecutive number, like: 1, 2, 3, ...

    >etc.


    Feel free to ask more questions!

    >The problem then becomes one of making that information available
    >to other *consumers*! I.e., wrapping it in a header file that
    >others can reference.


    Where's the problem? You create a header file and put
    the definitions in it:

    #define ERROR_NO_MORE_MEMORY_AVAILABLE 1
    #define ERROR_CANT_OPEN_AT_LEAST_ONE_FILE_FOR_READ_ACCESS 2
    ....
    #define ERROR_AT_LEAST_ONE_CLIENT_SUPPLIED_NUMERIC_VALIDITY_CONDITION_IS_NOT_FULFILLED 2351

    >A "solution" also needs to address the problem of *explaining*
    >the "result" (to the ultimate user).


    That's a separate problem of the application author.

    >very narrowly defined context: i.e., you can tell the user
    >"Multiple decimal points encountered" -- though you can't
    >indicate the role that the value being entered plays in the
    >application (is this a person's wages? the weight of a
    >newborn child? the average lifespan of a male tortoise?).


    This is known to the author of the application.

    >I currently do this with a mix of ad hoc measures.


    I use numeric values with meanings relative to a function
    and transform them when passing them upward to the next
    caller.

    For example,

    int filemove( LPTSTR const target, LPTSTR const source )
    { BOOL const success = MoveFile( source, target );
    int const terminate = success ? 1 : filecall_error();
    return terminate; }

    »MoveFile« returns »success« to describe its success,
    the semantics of which are being described in the
    »MoveFile« documentation.

    »filemove« uses an int value with semantics being
    described in the »filemove« documentation. This int
    value is being determined based on the result of two
    other functions called in »filemove«: »MoveFile«
    and »filecall_error«.

    There are no global semantics for result codes in
    this case.

    For a slightly larger example, see list1.c in

    http://www.purl.org/stefan_ram/pub/listenverarbeitung_in_c
     
    Stefan Ram, Mar 2, 2012
    #6
  7. Don Y

    Don Y Guest

    Hi William,

    On 3/1/2012 3:13 PM, William Ahern wrote:
    > Don Y<> wrote:
    > <snip>
    >> I currently do this with a mix of ad hoc measures. As such,
    >> it is very fragile (and an annoying drain on my time!). I'm
    >> hoping for suggestions that might lead me to a better/different
    >> approach (WITH THE SAME GOALS). Pointers to tools better suited
    >> to this. *Or*, examples of similar approaches!!

    >
    > With POSIX, at least, all errno values are positive. The few defined by C
    > are also positive. So I utilize the entire negative range for my error
    > identifiers.


    I don't have to cooperate with errno as any function interested in errno
    will examine it and fold it's *interpretation* of that error into the
    error that *it* reports.

    > I partition that space using a 3- or 4-character tag. So, for example, XML
    > library errors might start like
    >
    > enum {
    > XML_EBASE = -(('X'<< 24) | ('M'<< 16) | ('L'<< 8) | 32),
    > ...
    > XML_ELAST
    > };


    Oh, OK. But, you now have to keep track of which ranges ("tags") you've
    assigned. I am trying to eliminate all the housekeeping while still
    ensuring error codes are unique *and* easy to locate where they
    originate.

    E.g., where is XML_FOO thrown? Are you sure you have accounted for
    all sources of XML_FOO? (e.g., you have to grep the set of source
    files)

    > Minimal coordination is needed by different components, and you maintain
    > maximum composability going forward. (Not just in C, either.)
    >
    > I also always use an int instead of an enum to store and return errors,
    > otherwise things get ugly when, for instance, you have an interface that
    > takes a pointer to the error object.


    Understood.

    > By itself this doesn't solve all of the issues with error reporting, but the
    > above scheme is the best common denominator I've come up with. Every
    > component or library I write these days uses this scheme. It's simple enough
    > to then fold it into whatever broader error handling scheme is being used.
    > For me that usually means a simple strerror-type interface, with forwarding
    > from containers' to subcomponents' _strerror.


    But it makes the housekeeping something that you have to explicitly
    manage (and, potentially, "get wrong").

    I'm looking for an approach where the error sources and explanations
    are defined where they make most sense -- where they are *raised*.
    Then, extracted so that other agents can use them.

    Sort of like Literate Programming but only confined to error events.
     
    Don Y, Mar 2, 2012
    #7
  8. Don Y

    Don Y Guest

    Hi Shao,

    On 3/1/2012 3:53 PM, Shao Miller wrote:
    > On 3/1/2012 14:48, Don Y wrote:


    >> I have a suite of projects that utilize a common approach to
    >> error reporting. Instead of a PASS/FAIL result, most functions
    >> return information regarding the nature of the "failure" (which
    >> can also include "partial failures"... "warnings"). These
    >> reports allow upper levels of the application to convey those
    >> details to the user without exposing all of the *mechanism*
    >> involved to those upper levels.

    >
    > You might take a look at iPXE's error system. If I recall correctly,


    OK.

    > there's a range of bits for the error type, a range of bits for the
    > module (translation unit), and maybe another range or two I'm forgetting
    > about (maybe major and minor codes).


    This forces error "codes" to fit in a defined structure/form.
    And, still requires management of that "namespace" -- something
    has to ensure that this particular bit pattern is used ONLY
    for this module; this other pattern for this OTHER module, etc.

    Everything that you do "manually" is suspect. Are you *sure*
    there is no conflict or overlap between codes, etc.?

    I tried to work around that with the __FILE__, __LINE__ approach
    (I actually tie in __func__ as well). Ideally, I would use
    the value of the program counter associated with the "failed
    conditional" but that gets to be problematic for PIC.
    (consider how you would even know how to bind error descriptions
    to those codes without SOME a priori knowledge)

    > The special gift that iPXE's
    > primary author grants is the ability to look up the error codes on a
    > web-page. :)


    I plan on using the error codes and context to look up error
    messages from a genuine DBMS embedded in the devices. Hence
    the need to be able to pull the error messages out of the source
    files and use them to populate the tables, there.

    > If you are going to go with a strategy such as "warnings are positive"
    > and "errors are negative" and "success is 0," consider wrapping those
    > predicates with macros:
    >
    > if (WARNING(result = operation(arg1, arg2))) { /* ... */ } /* or */
    > if (SUCCESS(result = operation(arg1, arg2))) { /* ... */ } /* or */
    > if (ERROR(result = operation(arg1, arg2))) { /* ... */ } /* etc. */
    >
    > then the representation of 'result' needn't be considered and becomes an
    > implementation detail.


    Yes. The point was to be able to easily categorize a "code"
    as one of these. It would be problematic to separate warnings
    from errors if there was no EFFICIENT "scheme" involved (I
    don't want to have to lookup each "code" just to determine if
    the function succeeded, failed or was a "qualified success".)

    >> That approach is fine for "small" functions with a limited
    >> number of potential "results". But, consider how you would
    >> scale it to more comprehensive functions. E.g., the complete
    >> UI. Managing these "enumerations" gets to be tedious and
    >> error prone. "Which *values* have been assigned? What is
    >> a good value to pick for this new 'condition'? etc."

    >
    > If you have a single project, I'm not sure why you'd worry about "which
    > values have been assigned," since if you use macro/enum identifiers, you
    > can change these arbitrarily and recompile. "The last error number I
    > made up was 7. I need a new one. I guess I'll make it 8. No wait, this
    > one should come before the last one as it's alphabetically lower; no
    > problem."


    Note the "get value" example already uses that many different error
    categories.

    > If you're producing a library, then yeah, I don't think you'd wish to
    > change the header in an incompatible fashion in future revisions, as the
    > calling programs would break.


    Exactly. Even a tiny library is ~1KLoC. A small "subsystem" is about
    an order of magnitude larger than that.

    The scheme I outlined scales well -- albeit at the expense of a
    "make world" if you want to be sure that all dependencies are
    handled correctly (this can be done in just two passes over the
    sources *if* you are pedantic about where you allow error codes
    to be referenced in those sources -- e.g., NOT in conditional
    compilation)

    >> One approach to ensuring unique "values" for each of these
    >> "results" is to synthesize them from the function/file name
    >> and line number where they are detected (instantiating a
    >> macro at that particular point). This ensures that values
    >> are unique while hiding the *actual* value from the developer
    >> (*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
    >> to 0x27 or 0x7732!).
    >>
    >> The problem then becomes one of making that information available
    >> to other *consumers*! I.e., wrapping it in a header file that
    >> others can reference.

    >
    > That is something that functions happen to be particularly good at. A
    > header can declare a function:
    >
    > int ErrHasTooManyDecimalPoints(errtype_t test);
    >
    > and the caller need know nothing about the representation of 'errtype_t'
    > nor even the range of values... The predicate is what's important, and
    > it's identified symbolically, in this case.


    But you don't want the consumer to have to try applying each
    potential "ErrWHATEVER" to an error code that it encounters.

    Rather, give it an efficient means of testing if *ANY* error
    has occurred. Then, a separate means of resolving (and reporting)
    what the nature of that error actually is.

    > Or if you want the error implementation to be opaque to the lower-level
    > functions, you could have:
    >
    > int ErrHasTooManyDecimalPoints(errtype_t * errobj, int get_or_set);
    >
    >
    > The lower functions can include:
    >
    > /* ...function body... */
    > ErrHasTooManyDecimalPoints(&result, 1 /* set */ );
    >
    > and the caller could:
    >
    > /* ...function body... */
    > result = operation(arg1, arg2);
    > if (ErrHasTooManyDecimalPoints(&result, 0 /* get */ )) {
    > /* We know that one. Handle */
    > /* ... */
    > }
    >
    > But of course this seems a fair bit of extra work just to make the error
    > system opaque and symbolically accessible.


    I use the error code and context in a direct mapping to
    descriptions/remedies. The only symbolic references to
    error codes necessary are those *in* the actual source
    code -- assuming that the code wants to react to specific
    errors (e.g., ErrInsufficientMemory might cause the
    code to free up some resources and try, again)

    >> [Note this opens the door for a bootstrap problem but I am
    >> willing to live with that -- "I'll deal with it later..."]
    >>
    >> A "solution" also needs to address the problem of *explaining*
    >> the "result" (to the ultimate user). The point at which the
    >> result is "signaled" contains the most information about the
    >> nature of the "problem" being reported though it is in a
    >> very narrowly defined context: i.e., you can tell the user
    >> "Multiple decimal points encountered" -- though you can't
    >> indicate the role that the value being entered plays in the
    >> application (is this a person's wages? the weight of a
    >> newborn child? the average lifespan of a male tortoise?).
    >>
    >> So, the developer should be able to tie the explanation/commentary
    >> *to* the (symbolic) result code where the result code is defined
    >> instead of having to do so "somewhere else" -- hoping to keep the
    >> explanations in sync with the symbolic names, etc.


    > However, it's possible that you've already considered and dismissed
    > material akin to this response post's content. :)


    <grin> I've tried to think hard about the sorts of housekeeping
    to which any *manual* system would be vulnerable. Since I am
    operating in a rather "flush" environment, I am planning on
    using those resources to make the code and user interfaces
    more robust and full-featured.

    I'm, currently, just trying to come up with a more robust
    (less kludgey) toolset for integrating these mechanisms into
    the development process -- so others can take advantage of
    them instead of ignoring this aspect of the process
    ("Just throw a 'BAD_VALUE' error and generate a lengthy
    error message that lists ALL of the possible reasons that
    this message could be signaled -- and hope there are no
    bugs in the code that tests for each of them! Let the
    user sort out the problem...")
     
    Don Y, Mar 2, 2012
    #8
  9. Don Y

    Shao Miller Guest

    On 3/2/2012 01:05, Don Y wrote:
    >
    >> However, it's possible that you've already considered and dismissed
    >> material akin to this response post's content. :)

    >
    > <grin> I've tried to think hard about the sorts of housekeeping
    > to which any *manual* system would be vulnerable. Since I am
    > operating in a rather "flush" environment, I am planning on
    > using those resources to make the code and user interfaces
    > more robust and full-featured.
    >


    Just out of curiosity, did you skip over the 's_status' part of my
    previous response, or dismiss it as Not The Right Strategy For You?
     
    Shao Miller, Mar 2, 2012
    #9
  10. Don Y

    Don Y Guest

    Hi Stefan,

    On 3/1/2012 5:00 PM, Stefan Ram wrote:
    > Supersedes:<-berlin.de>
    > [removed "list0.c" with Supersedes]
    >
    > Don Y<> writes:
    >> Managing these "enumerations" gets to be tedious and error
    >> prone. Which *values* have been assigned?

    >
    > That's easy. Just keep a single table with two rows:
    > number and meaning. There, you can always find the
    > answer to this question. (You can use the include
    > file with the define-directives.)


    You need to maintain this "by hand". There is nothing that
    prevents you from:
    #define YES (2)
    #define NO (2)

    Nor:
    #define YES (2)
    ...
    #define ABSOLUTELY (27)
    (assuming yes and absolutely are synonyms)

    There is nothing that ensures:
    #define TOO_MANY_DIGITS (375)
    is actually *used* anywhere! Does its absence mean that some
    test has been forgotten in the code? Or, that the test has
    been made unnecessary (and, thus, the error code associated
    with it) due to a change in the implementation?

    You have to maintain one such table for each library/subsystem
    (having one for the entire application is just silly -- if it
    has to be maintained by hand!)

    And, if you have multiple such tables, you have to ensure the
    "number spaces" for each do not overlap.

    I.e., it forces all of the housekeeping onto the developer.

    >> What is a good value to pick for this new 'condition'?

    >
    > The next consecutive number, like: 1, 2, 3, ...


    This implies you have *all* of the numbers in one place.
    And, that none of the subsystems/libraries are ever enhanced.
    ("Gee, I need to verify the value entered doesn't overflow
    a double. Let me create a new error code DOUBLE_OVERFLOW
    and I'll just assign it the value after MOTOR_OVERHEATED...")

    How do you find which errors are thrown by each module/library/etc.?
    How do you ensure you don't already have "OVERFLOW_DOUBLE" hidden
    away in that SINGLE long list of error codes?

    >> etc.

    >
    > Feel free to ask more questions!
    >
    >> The problem then becomes one of making that information available
    >> to other *consumers*! I.e., wrapping it in a header file that
    >> others can reference.

    >
    > Where's the problem? You create a header file and put
    > the definitions in it:
    >
    > #define ERROR_NO_MORE_MEMORY_AVAILABLE 1
    > #define ERROR_CANT_OPEN_AT_LEAST_ONE_FILE_FOR_READ_ACCESS 2
    > ...
    > #define ERROR_AT_LEAST_ONE_CLIENT_SUPPLIED_NUMERIC_VALIDITY_CONDITION_IS_NOT_FULFILLED 2351


    See above.

    >> A "solution" also needs to address the problem of *explaining*
    >> the "result" (to the ultimate user).

    >
    > That's a separate problem of the application author.


    No! That's what leads to "bad value" type error messages!
    The application doesn't want to be concerned with the details of
    "what makes a particular input string a valid numeric indicator".
    It wants to *bury* that information and those criteria inside
    a tool that it then *uses* to perform that operation for it.

    A given layer in an application should only be concerned with
    explaining the issues that *it* enforces. Should the UI be
    responsible for identifying the reason why keystrokes are
    not available from the "keyboard device"? That would imply
    that the UI would need to know *how* the keyboard device
    works and the sorts of things that could go wrong with it.

    Likewise, should a function that gets the setpoint for a
    temperature controller from the user know what the *actual*
    syntax of a "valid temperature specification" is? And,
    *how* the user erred in specifying that value?

    >> very narrowly defined context: i.e., you can tell the user
    >> "Multiple decimal points encountered" -- though you can't
    >> indicate the role that the value being entered plays in the
    >> application (is this a person's wages? the weight of a
    >> newborn child? the average lifespan of a male tortoise?).

    >
    > This is known to the author of the application.


    The application *layer* that is responsible for this is
    where the error can best be explained. Anything below that
    doesn't have sufficient knowledge of *context* to explain
    it meaningfully. Anything *above* that doesn't want to be
    concerned with this level of detail (see above).

    >> I currently do this with a mix of ad hoc measures.

    >
    > I use numeric values with meanings relative to a function
    > and transform them when passing them upward to the next
    > caller.
    >
    > For example,
    >
    > int filemove( LPTSTR const target, LPTSTR const source )
    > { BOOL const success = MoveFile( source, target );
    > int const terminate = success ? 1 : filecall_error();
    > return terminate; }
    >
    > »MoveFile« returns »success« to describe its success,
    > the semantics of which are being described in the
    > »MoveFile« documentation.
    >
    > »filemove« uses an int value with semantics being
    > described in the »filemove« documentation. This int
    > value is being determined based on the result of two
    > other functions called in »filemove«: »MoveFile«
    > and »filecall_error«.


    And how does the person *using* the application that encapsulates
    this code know what's gone wrong with his *use* of the application?

    > There are no global semantics for result codes in
    > this case.


    filemove exposes the error from MoveFile to upper levels.
    I.e., the error codes returned by MoveFile() *include*
    (and, thus, have the potential to conflict with) those
    of filemove()).

    How do you explain the error to the user -- unless you require
    MoveFile to be aware of all of the things that can happen
    *inside* filemove? When filemove changes (possibly recognizing
    NEW error conditions or *different* error conditions), then
    MoveFile needs to be able to explain those new "problems"
    for the user.

    You haven't isolated the responsibilities.

    (Does main() have code in it to explain errors that are essentially
    percolated upwards from filemove() -- regardless of how *deep* in
    the application the error was detected?)

    > For a slightly larger example, see list1.c in
    >
    > http://www.purl.org/stefan_ram/pub/listenverarbeitung_in_c
     
    Don Y, Mar 2, 2012
    #10
  11. Don Y

    Don Y Guest

    Hi Shao,

    On 3/1/2012 11:50 PM, Shao Miller wrote:
    > On 3/2/2012 01:05, Don Y wrote:
    >>
    >>> However, it's possible that you've already considered and dismissed
    >>> material akin to this response post's content. :)

    >>
    >> <grin> I've tried to think hard about the sorts of housekeeping
    >> to which any *manual* system would be vulnerable. Since I am
    >> operating in a rather "flush" environment, I am planning on
    >> using those resources to make the code and user interfaces
    >> more robust and full-featured.

    >
    > Just out of curiosity, did you skip over the 's_status' part of my
    > previous response, or dismiss it as Not The Right Strategy For You?


    I'm trying to avoid complicating the discussion with the introduction
    of mechanisms of passing "qualifying information" (what you call
    "extended status information") up to the caller. This is a whole
    'nother can of worms as each potential error/result could potentially
    have its own idea as to "what's important/pertinent".

    My current approach just focuses on indicating *where* the "test
    failed" and in which context that was encountered.

    E.g., imagine someone says the application wasn't accepting their
    "input" (cf the "get value" example). People are notoriously
    inaccurate at telling you the *exact* message that they are
    receiving:
    "I typed in my age but it said the number I typed was bad"
    "No, I'm sure it didn't say that (because I *know* what all of
    the error messages are and none of them are 'the number was bad')"
    "Well, that's what it *meant*! I can't remember the actual WORDING..."
    "Could you do whatever it was you were doing and provide me with
    the error identifier located at the end of the message?"
    "OK, it says _______"
    "Ah, you've just typed in a '-' sign but you did so after you
    started typing in the numeric value/digits. If you want the value
    to be negative, you need to type the '-' sign first. OTOH, if you
    are trying to type '2012-1965' and hoping the machine will interpret
    that as 47, I'm sorry but the machine doesn't have that capability..."

    I'm not worried (in this discussion) about providing the extra
    details (e.g., "2012-1965") to better explain/understand the
    nature of the error to that finer degree.
     
    Don Y, Mar 2, 2012
    #11
  12. Don Y <> writes:
    [...]
    > You need to maintain this "by hand". There is nothing that
    > prevents you from:
    > #define YES (2)
    > #define NO (2)
    >
    > Nor:
    > #define YES (2)
    > ...
    > #define ABSOLUTELY (27)
    > (assuming yes and absolutely are synonyms)

    [...]

    A minor point: parenthesizing macro definitions is a good habit, but
    it's not necessary when the macro expands to a single token. This:

    #define ABSOLUTELY 27

    is just as safe as

    #define ABSOLUTELY (27)

    --
    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, Mar 2, 2012
    #12
  13. Don Y

    Kaz Kylheku Guest

    On 2012-03-02, Keith Thompson <> wrote:
    > Don Y <> writes:
    > [...]
    >> You need to maintain this "by hand". There is nothing that
    >> prevents you from:
    >> #define YES (2)
    >> #define NO (2)
    >>
    >> Nor:
    >> #define YES (2)
    >> ...
    >> #define ABSOLUTELY (27)
    >> (assuming yes and absolutely are synonyms)

    > [...]
    >
    > A minor point: parenthesizing macro definitions is a good habit, but
    > it's not necessary when the macro expands to a single token. This:
    >
    > #define ABSOLUTELY 27
    >
    > is just as safe as
    >
    > #define ABSOLUTELY (27)


    Safer. The former ABSOLUTELY above can be subject to token pasting.

    #define XPASTE(X, Y) X ## Y
    #define PASTE(X, Y) XPASTE(X, Y)

    PASTE(FOO_, ABSOLUTELY) /* result: FOO_27 */

    If ABSOLUTELY is (27) then the above is undefined behavior, since
    pasting FOO_ with ( is an invalid token.

    I.e. #define ABSOLUTELY 27 is, effectively, not only a constant expression
    evaluating to 27, but it is lexically a numeric token, which can be desireable.
     
    Kaz Kylheku, Mar 2, 2012
    #13
  14. In article <>,
    Keith Thompson <> wrote:
    >Don Y <> writes:
    >[...]
    >> You need to maintain this "by hand". There is nothing that
    >> prevents you from:
    >> #define YES (2)
    >> #define NO (2)
    >>
    >> Nor:
    >> #define YES (2)
    >> ...
    >> #define ABSOLUTELY (27)
    >> (assuming yes and absolutely are synonyms)

    >[...]
    >
    >A minor point: parenthesizing macro definitions is a good habit, but
    >it's not necessary when the macro expands to a single token. This:
    >
    > #define ABSOLUTELY 27
    >
    >is just as safe as
    >
    > #define ABSOLUTELY (27)


    Much as I hate to disagree with Leader Kiki, I have to take exception to
    this. If there is a corporate requirement that all macro definitions be
    parenthesized, as is probably the case in many workplaces, then not
    parenthesizing exposes the coder to the risk of ending up on the
    unemployment line.

    Hardly safe by my lights...

    --
    Just for a change of pace, this sig is *not* an obscure reference to
    comp.lang.c...
     
    Kenny McCormack, Mar 2, 2012
    #14
  15. Don Y

    Don Y Guest

    Hi Keith,

    On 3/2/2012 3:05 AM, Keith Thompson wrote:

    > A minor point: parenthesizing macro definitions is a good habit, but
    > it's not necessary when the macro expands to a single token. This:


    Keeping a gun's safety "on" is "a good habit". Do you often
    leave it *off* just because you don't *think* you need it
    "on" at the present time? Or, do you wait until you
    really *need* it "off" (i.e., just prior to discharge)?

    Good habits are kept -- as a matter of HABIT! :>
     
    Don Y, Mar 2, 2012
    #15
  16. Don Y

    James Kuyper Guest

    On 03/02/2012 12:46 PM, Don Y wrote:
    > Hi Keith,
    >
    > On 3/2/2012 3:05 AM, Keith Thompson wrote:
    >
    >> A minor point: parenthesizing macro definitions is a good habit, but
    >> it's not necessary when the macro expands to a single token. This:

    >
    > Keeping a gun's safety "on" is "a good habit". Do you often
    > leave it *off* just because you don't *think* you need it
    > "on" at the present time? Or, do you wait until you
    > really *need* it "off" (i.e., just prior to discharge)?
    >
    > Good habits are kept -- as a matter of HABIT! :>


    I check my keys every time I go out the door of my house, as a matter of
    habit, even if I don't intend to lock the door. That's a good habit.
    People with OCD might check their keys each time they go out the bedroom
    door, even if it doesn't have a lock. That's not a good habit, that's a
    waste of time. In extreme cases, people with OCD waste so much time
    checking things that don't need to be checked, that they never get
    anything useful done with their life.

    Parentheses convert other kinds of expressions into primary expressions.
    Macro expansions that are already primary expressions (identifiers,
    constants, string literals, and generic selections* - 6.5.1) - don't
    need parentheses. Parenthesizing them is closer to the OCD end of the
    spectrum, than to the good habit end.

    *Generic selections are a new feature of C2011.
     
    James Kuyper, Mar 2, 2012
    #16
  17. Don Y

    Don Y Guest

    Hi James,

    On 3/2/2012 12:08 PM, James Kuyper wrote:

    >>> A minor point: parenthesizing macro definitions is a good habit, but
    >>> it's not necessary when the macro expands to a single token. This:

    >>
    >> Keeping a gun's safety "on" is "a good habit". Do you often
    >> leave it *off* just because you don't *think* you need it
    >> "on" at the present time? Or, do you wait until you
    >> really *need* it "off" (i.e., just prior to discharge)?
    >>
    >> Good habits are kept -- as a matter of HABIT! :>

    >
    > I check my keys every time I go out the door of my house, as a matter of
    > habit, even if I don't intend to lock the door. That's a good habit.
    > People with OCD might check their keys each time they go out the bedroom
    > door, even if it doesn't have a lock. That's not a good habit, that's a
    > waste of time. In extreme cases, people with OCD waste so much time
    > checking things that don't need to be checked, that they never get
    > anything useful done with their life.


    OCD interferes with your goal -- "living".

    > Parentheses convert other kinds of expressions into primary expressions.
    > Macro expansions that are already primary expressions (identifiers,
    > constants, string literals, and generic selections* - 6.5.1) - don't
    > need parentheses. Parenthesizing them is closer to the OCD end of the
    > spectrum, than to the good habit end.


    I guess I don't see two extra keystrokes on a #define as interfering
    with my goal (of writing reliable code that others can maintain).
    I've already invested 10 keystrokes ("#define " the whitespace between
    the symbol and its definition and the trailing '\n') and will invest
    at least 2 more (assuming the symbol and definition are each just 1).
    Increasing that "overhead" from 12 to 14 is pocket change.

    OTOH, I can't count the number of times I've had to step in and
    "fix" someone's "minor tweek" of a running program when they
    changed:
    #define PHONE_NUMBER_DIGITS 7
    to:
    #define PHONE_NUMBER_DIGITS 3+7
    And then have to *explain* the reason behind the *need* for the parens:
    "So, if I just said '10', instead, I wouldn't have had the problem
    AND wouldn't have had to type the parens? I guess I should just
    type '10' in the future..."
    "No, the problem with *that*, is..."

    I can't speak for you but *I* sure don't like wasting my time on
    that sort of after-the-fact annoyance.

    Of course, you're free to live with whatever coding style you
    (and your clients/employers) find suitable for the projects
    and personnel available to you.

    You could also build giant tables of #define's to represent all
    of the possible error codes that routines in your project can
    throw! :>

    [I'd really prefer to address the subject of my OP. Missing the
    forest for the trees is a sure-fire "waste of time" :>]
     
    Don Y, Mar 2, 2012
    #17
  18. Don Y

    Kaz Kylheku Guest

    On 2012-03-02, Don Y <> wrote:
    > Hi Keith,
    >
    > On 3/2/2012 3:05 AM, Keith Thompson wrote:
    >
    >> A minor point: parenthesizing macro definitions is a good habit, but
    >> it's not necessary when the macro expands to a single token. This:

    >
    > Keeping a gun's safety "on" is "a good habit". Do you often
    > leave it *off* just because you don't *think* you need it
    > "on" at the present time? Or, do you wait until you
    > really *need* it "off" (i.e., just prior to discharge)?


    Do you often modify your gun to a completely different model,
    and without touching the safety switch?
     
    Kaz Kylheku, Mar 2, 2012
    #18
  19. Don Y

    Ian Collins Guest

    On 03/ 2/12 11:05 PM, Keith Thompson wrote:
    > Don Y<> writes:
    > [...]
    >> You need to maintain this "by hand". There is nothing that
    >> prevents you from:
    >> #define YES (2)
    >> #define NO (2)
    >>
    >> Nor:
    >> #define YES (2)
    >> ...
    >> #define ABSOLUTELY (27)
    >> (assuming yes and absolutely are synonyms)

    > [...]
    >
    > A minor point: parenthesizing macro definitions is a good habit, but
    > it's not necessary when the macro expands to a single token. This:
    >
    > #define ABSOLUTELY 27
    >
    > is just as safe as
    >
    > #define ABSOLUTELY (27)


    Or simply don't use macros for constants!

    --
    Ian Collins
     
    Ian Collins, Mar 2, 2012
    #19
  20. Don Y

    Ben Pfaff Guest

    Keith Thompson <> writes:

    > Don Y <> writes:
    > A minor point: parenthesizing macro definitions is a good habit, but
    > it's not necessary when the macro expands to a single token. This:
    >
    > #define ABSOLUTELY 27
    >
    > is just as safe as
    >
    > #define ABSOLUTELY (27)


    Furthermore,

    #define PRIx64 "llx"

    is far more useful than

    #define PRIx64 ("llx")
    --
    char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
    ={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
    =b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
    2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
     
    Ben Pfaff, Mar 2, 2012
    #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. Steven T. Hatton
    Replies:
    6
    Views:
    4,263
    Steven T. Hatton
    Apr 12, 2004
  2. Sakesun Roykiattisak
    Replies:
    1
    Views:
    244
    Christopher T King
    Aug 5, 2004
  3. laredotornado
    Replies:
    4
    Views:
    1,309
    Daniel Pitts
    Sep 23, 2011
  4. Sarah Klaum

    Bind to annotated typed dataset

    Sarah Klaum, Apr 30, 2004, in forum: ASP .Net Datagrid Control
    Replies:
    0
    Views:
    160
    Sarah Klaum
    Apr 30, 2004
  5. Laszlo Nagy
    Replies:
    1
    Views:
    88
    Ned Batchelder
    Nov 18, 2013
Loading...

Share This Page