Changing the return type of a function from void to int

Discussion in 'C Programming' started by C++Liliput, May 9, 2011.

  1. C++Liliput

    C++Liliput Guest

    Hi,
    I have a set of APIs that currently have a void return type. I want
    to change this to int because I am wrapping around these APIs in JNI
    and want to throw exceptions under certain error conditions. Since
    that is possible only if I return an int (that denotes an error
    condition), my question is this - does changing the return type of a
    function from void to int break any backward compatibility with the
    older clients of the API? It doesn't look like it since the older
    clients can continue to use the new APIs in the void context. Are
    there any other pitfalls to this change?

    Thanks
    Aveek
     
    C++Liliput, May 9, 2011
    #1
    1. Advertisements

  2. C++Liliput

    Shao Miller Guest

    Do you mean if the older clients are recompiled to use modified headers?
    Or do you mean that the older clients remain the way they are but will
    be calling into a modified library where these functions now return
    'int' instead of 'void'?

    For the latter, I might be worried a bit about n1256.pdf's 6.5.2.2p9.
    The older clients would be calling the functions using a function type
    other than how the functions are defined in the newly-compiled library.
    If that results in undefined behaviour, and outside of the scope of C,
    if a stack is used to return function values, and if the caller is
    expected to clean up that stack after a function call, the older clients
    would not be cleaning very well by assuming a 'void' return type.

    Or maybe I'm wrong and in:

    typedef void f_ret_void(int);
    typedef int f_ret_int(int);

    the types 'f_ret_void' and 'f_ret_int' are compatible. That doesn't
    seem quite right, though. :)

    Perhaps this is a non-issue in your environment, though. Does the
    product/do the products need to be utterly portable in a standard sense?
     
    Shao Miller, May 9, 2011
    #2
    1. Advertisements

  3. As far as the C language is concerned, a function returning int is
    simply incompatible with a function returning void, and the behavior of
    a program that calls one such function as if it were the other is
    undefined.

    It may be that you can get away with it on your platform, but that's a
    question about your platform, not about C.
     
    Keith Thompson, May 9, 2011
    #3
  4. C++Liliput

    Fred Guest

    So you are saying that the statement
    printf( "Hello, World!\n" );
    provokes undefined behavior, since I am calling it
    as if it were a function returning void rather than
    int n;
    n = printf( "Hello, World!\n" );
    where I am calling it as a function returning an int?
     
    Fred, May 9, 2011
    #4
  5. No, not at all.

    If you have the required #include <stdio.h>, then the correct
    declaration of printf (returning int) is visible to the compiler
    when it compiles the call. It generates code that calls printf()
    with the specified arguments, then discards the result.

    On the other hand, if you omit the #include, and instead try to
    declare printf yourself as a void function, then the behavior
    is undefined:

    extern void printf(const char *format, ...);

    int main(void)
    {
    printf("Hello, World!\n");
    return 0;
    }

    And if you omit the declaration altogether, then a C90 compiler
    will implicitly assume that the unknown function "printf" returns
    int -- but it will also assume that it takes a fixed number of
    arguments based on the call, whereas printf is actually variadic.
    Since fixed-argument and variadic functions can use different calling
    conventions, again, the behavior is undefined. In C99, calling a
    function without a visible declaration is a constraint violation;
    if the compiler chooses to generate an executable after issuing
    a warning, again, the language doesn't define the behavior of the
    resulting program. A sufficiently clever compiler might recognize
    the name "printf" and warn you that you're doing something wrong,
    but that's not required.

    It's common for funtions returning int and functions returning void
    to be "compatible" in practice. For example, an int function might
    store its result in a specified CPU register; calling it as if it
    were a void function merely ignores whatever is in that register.
    But other calling schemes are possible.

    Basically, if you lie to the compiler, all bets are off.
     
    Keith Thompson, May 9, 2011
    #5
  6. C++Liliput

    Shao Miller Guest

    I don't think he's saying that.

    I believe that the expression for the called function, 'printf' in this
    instance, is the same regardless of what you are doing with the result
    of the function call. And in your former case, I think that you simply
    have a "void expression," which is evaluated.

    The same as:

    int n = 3;
    n;

    You might chop it up thusly:

    [ [ [printf] [ [(] ["Hello, world!\n"] [)] ] ] [;] ]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    and:

    [ [ [n] [=] [ [printf] [ [(] ["Hello, world!\n"] [)] ] ] ] [;] ]
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    The "outer" expression for the assignment of 'n' should not influence
    the "inner" expression for the function call; that expression is a
    sub-expression in its own right, if I understand correctly. :)
     
    Shao Miller, May 9, 2011
    #6
  7. [...]

    Not quite. A void expression would be an expression whose type is void.
    There is no void expression in the statement
    printf( "Hello, World!\n" );

    [consulting the standard]

    Hang on, maybe there is. C99 6.8.3 describes statement expressions (an
    expression with a semicolon added to the end of it can be used as a
    statement). The semantics are:

    The expression in an expression statement is evaluated as a void
    expression for its side effects.

    Frankly, I find that wording a bit misleading. I would have said that
    the expression is evaluated for its side effects, and any result is
    discarded.

    Given the current wording, I suppose one could argue that evaluating a
    printf call "as a void expression" means calling printf *as if* it
    returned void, and therefore the behavior is undefined. But I'm certain
    that that's not the intent, since it would break most C programs.

    Looks like another question for comp.std.c.
     
    Keith Thompson, May 9, 2011
    #7
  8. C++Liliput

    Shao Miller Guest

    On 5/9/2011 1:51 PM, Keith Thompson wrote:
    ....C99 6.8.3 describes statement expressions (an
    I'm certain of the same, but not so certain one could argue that
    argument. Since the outermost expression is a function call, and that
    expression has a result type, then I think 6.3.2.2p1 would allow for the
    value to be discarded just as you suggest it ought.
     
    Shao Miller, May 9, 2011
    #8
  9. Please don't presume to tell others what they are saying. Your
    assertion beginning with "So you are saying" is simply false. It is not
    true that Keith was saying what follows, and for a simple reason: what
    follows is completely false. You are _not_ calling it as a function
    returning void; you are simply discarding the return value.
    So, in addition to making false claims about what Keith wrote, you are
    showing a lack of familiarity with elementary aspects of the C language.
     
    Martin Ambuhl, May 9, 2011
    #9
  10. C++Liliput

    Shao Miller Guest

    On 5/9/2011 1:51 PM, Keith Thompson wrote:
    ....C99 6.8.3 describes statement expressions (an
    I'm certain of the same, but not so certain one could argue that
    argument. Since the outermost expression is a function call, and that
    expression has a result type, then I think 6.3.2.2p1 would allow for the
    value to be discarded just as you suggest it ought.
     
    Shao Miller, May 9, 2011
    #10
  11. Given the wording of C99 6.8.3p2, which says that the call "is
    evaluated as a void expression", it's not an unreasonable question.
    (And yes, it was a question, not an assertion; note the question
    mark at the end. "are you" might have been better than "you are",
    but I'm not going to worry about it.)

    Fred, was your question based on a (mis)reading of C99 6.8.3p2?
    I'm arguing in comp.std.c that it should be re-worded; showing that
    someone was actually led astray by the current wording would help
    my argument.
     
    Keith Thompson, May 9, 2011
    #11
  12. C++Liliput

    Fred Guest

    It all goes back to Shao Miller's first response to the OP, where he
    lists two scenarios - one recompiling with new headers, and one just
    linking to the new libraries without recompiling.

    The former is fine, the latter is not.

    But in the earlier responses no one explained to the OP the difference
    between calling a void function and calling a non-void function and
    discarding the results.

    Also, some programmers may not understand what is meant by "discarding
    the result"; i.e., that
    printf( ...);
    discards the result of printf, whereas there is nothing to discard
    from a call to a void function, such as
    qsort(...);
     
    Fred, May 9, 2011
    #12
  13. C++Liliput

    James Kuyper Guest

    On 05/09/2011 02:14 PM, Fred wrote:
    ....
    The expression

    printf("Hello, World!\n")

    results in a value of type int. The expression

    n = printf( "Hello, World!\n" )

    also results in a value of type int. If the type of the first expression
    would render the behavior of the corresponding expression statement
    undefined, why wouldn't that also be true of the second expression,
    which has the same type?
     
    James Kuyper, May 9, 2011
    #13
  14. And it turns out that the phrase "evaluated as a void expression" is
    defined by the standard (C99 6.3.2.2p1), so my objection to the current
    wording of 6.8.3p2 is much weaker than I thought it was.
    The compiler needs to have a consistent view of how a function is
    defined/declared. Suppose you have a function defined in foo.c, and
    declared in foo.h, as returning void; bar.c has a #include "foo.h" and
    calls the function. If you change both foo.c and foo.h so the function
    returns int, and recompile everything, you're fine. If you change foo.h
    and then recompile bar.c *without* recompiling the function definition,
    you're lying to the compiler, and the behavior is undefined.
    Right. A better way to phrase it might be "discarding the result,
    if any".
     
    Keith Thompson, May 9, 2011
    #14
  15. C++Liliput

    Borophyll Guest

    No one is making any assertions. Don't be confused by interrogative
    sentences that appear to have a declarative syntax. (Hint: the
    question mark at the end gives it away...)
     
    Borophyll, May 10, 2011
    #15
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.