Re: On the interchangeability of (void *) and (char *) to printf()

Discussion in 'C Programming' started by Tim Rentsch, Feb 13, 2009.

  1. Tim Rentsch

    Tim Rentsch Guest

    Han from China <> writes:

    > Barry Schwarz wrote:
    > > 6.2.5p27 requires char* and void* to have the same representation and
    > > alignment which may be what you meant. Even then, there is no requirement
    > > that void* and char* be passed to printf the same way.

    >
    > That argument is made by those who don't accept the non-normative
    > footnote to 6.2.5{27}: "The same representation and alignment requirements
    > are meant to imply interchangeability as arguments to functions ...."
    >
    > A while back, Tim Rentsch mentioned 7.15.1.1{2}, which describes the
    > va_arg() macro and provides a normative statement for the interchangeability
    > of (void *) and (char *) arguments in general variadic functions.
    >
    > To demonstrate the interchangeability of (void *) and (char *) as
    > arguments to printf(), it is therefore necessary to find some normative
    > statement that places printf() in the category of a general variadic
    > function calling the va_arg() macro to process its "..." list.
    >
    > I propose for discussion 7.19.6.10{2}, which describes the vprintf()
    > function:
    >
    > "The vprintf function is equivalent to printf, with the variable
    > argument list replaced by arg..."
    >
    > Unfortunately, this statement appears open to multiple interpretations,
    > so I'm not sure whether we can gain any traction. Of possible further
    > interest is the non-normative footnote #254 (which a definitive
    > argument would have to do without, of course):
    >
    > "As the functions ... vprintf ... invoke the va_arg macro ...."
    >
    > Suppose we have our own variadic function in which we initialize
    > a va_list object. We're assured that (char *) and (void *) are
    > interchangeable arguments to our function. If we pass that va_list
    > object to vprintf(), presumably the interchangeability should
    > still hold and so vprintf() works fine (with a (char *) for %p,
    > for instance). I don't think you need footnote #254 to see that
    > vprintf() allows (char *) and (void *) interchangeability -- the
    > interface pretty much implies it (maybe not?).
    >
    > Now, depending on how one interprets the 7.19.6.10{2} statement
    > given above, especially the words "equivalent" and "replaced", it
    > would seem that a case could be made that printf() borrows the
    > interchangeability property of vprintf() (assuming that property
    > has in fact been demonstrated).


    Certainly the text in 7.19.6.10, and also the text in 7.19.6.8, and
    also footnote 254, provide evidence that reading the provisions of
    7.15.1.1p2 as applying to fprintf(), etc, is a more reasonable
    interpretation than that they don't.

    Furthermore, there's also evidence in 7.1.4p{1,2}, even if not
    so direct, supporting the same interpretation.

    Finally, consider 7.15. This section specifies the only mechanism
    described in the standard for accessing arguments other than those
    corresponding to named parameters. It's reasonable to infer that this
    mechanism is what's used for fprintf(), etc, given the prototypes
    specified for them, since it's the only such mechanism described.
    Otherwise, the library functions accessing such parameters use an
    unspecified mechanism, with undefined semantics -- in other words,
    undefined behavior. If 7.15 doesn't define the semantics of
    accessing variadic functions for library functions, which part of
    the Standard does? Unless some particular section(s) can be pointed
    to as defining those semantics, they aren't defined, and that's
    undefined behavior.

    So, for purposes of comp.lang.c, I think it's reasonable to say
    the issue is closed. Perhaps it makes sense to continue the
    debate in the context of comp.std.c, but in terms of how the
    Standard will actually be read and understood by implementors,
    the only reasonable expectation is that (void*) and (char*)
    must be interchangeable in fprintf(), etc, in the same way
    that they are for user-defined functions using va_arg().


    > There is a danger: Even if a normative argument somehow succeeds,
    > the argument is so twisted that you could hardly expect every
    > implementor to learn of it. At the end of the day, you're probably
    > better off using your casts anyway.


    I reach the same conclusion but for a different reason. I think
    casting a (void*) argument to (char*) (or sometimes vice versa) for
    variadic arguments is simply better style, and also may help with
    lint-like tools (or, lord helps us, a future release of GCC). No real
    world implementation is ever going to exhibit different behavior for
    (void*) and (char*) in variadic arguments to fprintf(), etc, because
    doing so would be more work than simply using the mechanisms supplied
    in <stdarg.h>, which must be there anyway.
     
    Tim Rentsch, Feb 13, 2009
    #1
    1. Advertising

  2. Tim Rentsch

    Tim Rentsch Guest

    Barry Schwarz <> writes:

    > On 13 Feb 2009 10:40:35 -0800, Tim Rentsch <>
    > wrote:
    >
    >
    > snip
    >
    > >Finally, consider 7.15. This section specifies the only mechanism
    > >described in the standard for accessing arguments other than those
    > >corresponding to named parameters. It's reasonable to infer that this
    > >mechanism is what's used for fprintf(), etc, given the prototypes
    > >specified for them, since it's the only such mechanism described.
    > >Otherwise, the library functions accessing such parameters use an
    > >unspecified mechanism, with undefined semantics -- in other words,
    > >undefined behavior. If 7.15 doesn't define the semantics of
    > >accessing variadic functions for library functions, which part of
    > >the Standard does? Unless some particular section(s) can be pointed
    > >to as defining those semantics, they aren't defined, and that's
    > >undefined behavior.

    >
    > There is no requirement that the library functions (or the compiler
    > for that matter) be written in C. Assuming they are restricted to
    > features defined in the language is unjustified.


    I think you missed the point. Whether library functions are written
    in C or in ancient Babylonian assembly language, the semantics of how
    their parameters are transmitted must be defined within the Standard;
    if there is no such definition, calling a library function would be
    undefined behavior, no matter how it's implemented. Until someone can
    point out an alternative, the only candidates are regular parameter
    transmission for ordinary arguments, and <stdarg.h> transmission for
    variadic arguments. The mechanism for collecting arguments (the
    implementation) can be anything at all; but the semantics of what
    parameter values correspond to which argument values, and what
    processing is done on those parameter values, must be defined within
    the Standard -- otherwise it's undefined behavior.
     
    Tim Rentsch, Feb 14, 2009
    #2
    1. Advertising

  3. On 14 Feb 2009 12:22:25 -0800, Tim Rentsch <>
    wrote:

    >Barry Schwarz <> writes:
    >
    >> On 13 Feb 2009 10:40:35 -0800, Tim Rentsch <>
    >> wrote:
    >>
    >>
    >> snip
    >>
    >> >Finally, consider 7.15. This section specifies the only mechanism
    >> >described in the standard for accessing arguments other than those
    >> >corresponding to named parameters. It's reasonable to infer that this
    >> >mechanism is what's used for fprintf(), etc, given the prototypes
    >> >specified for them, since it's the only such mechanism described.
    >> >Otherwise, the library functions accessing such parameters use an
    >> >unspecified mechanism, with undefined semantics -- in other words,
    >> >undefined behavior. If 7.15 doesn't define the semantics of
    >> >accessing variadic functions for library functions, which part of
    >> >the Standard does? Unless some particular section(s) can be pointed
    >> >to as defining those semantics, they aren't defined, and that's
    >> >undefined behavior.

    >>
    >> There is no requirement that the library functions (or the compiler
    >> for that matter) be written in C. Assuming they are restricted to
    >> features defined in the language is unjustified.

    >
    >I think you missed the point. Whether library functions are written
    >in C or in ancient Babylonian assembly language, the semantics of how
    >their parameters are transmitted must be defined within the Standard;


    I'm pretty sure I disagree with this but I'll wait till you define
    what you mean by semantics in this context.

    >if there is no such definition, calling a library function would be
    >undefined behavior, no matter how it's implemented. Until someone can
    >point out an alternative, the only candidates are regular parameter
    >transmission for ordinary arguments, and <stdarg.h> transmission for
    >variadic arguments. The mechanism for collecting arguments (the
    >implementation) can be anything at all; but the semantics of what


    If the mechanism can be anything at all, it need not be related to
    anything in stdarg.h. stdarg.h provides only one of many possible
    mechanisms. The one that the compiler will use for code you compile.
    It does not mean that library functions must use it.

    >parameter values correspond to which argument values, and what


    I'll agree with the correlation between arguments and parameters.

    >processing is done on those parameter values, must be defined within
    >the Standard -- otherwise it's undefined behavior.


    Processing done on the parameters by programs coded in C (like all
    other processing by such programs) must be defined by the standard (or
    designated as unspecified or implementation defined, etc). Processing
    done by other programs is obviously not covered by the standard. The
    only requirement on a library function is that it must comply with the
    interface specified in the standard (name, types of arguments, and
    type and meaning of return value if any). How they do so is up the
    implementation. A library function is free to use the tools provided
    in stdarg.h OR NOT.

    It wouldn't surprise me if many library functions, such as fopen or
    malloc, cannot be written in standard C because they must use system
    specific features for which the language provides no tools. Once the
    door is open, there is no reason printf can't walk through also.

    --
    Remove del for email
     
    Barry Schwarz, Feb 15, 2009
    #3
  4. Tim Rentsch

    Tim Rentsch Guest

    Barry Schwarz <> writes:

    > On 14 Feb 2009 12:22:25 -0800, Tim Rentsch <>
    > wrote:
    >
    > >Barry Schwarz <> writes:
    > >
    > >> On 13 Feb 2009 10:40:35 -0800, Tim Rentsch <>
    > >> wrote:
    > >>
    > >>
    > >> snip
    > >>
    > >> >Finally, consider 7.15. This section specifies the only mechanism
    > >> >described in the standard for accessing arguments other than those
    > >> >corresponding to named parameters. It's reasonable to infer that this
    > >> >mechanism is what's used for fprintf(), etc, given the prototypes
    > >> >specified for them, since it's the only such mechanism described.
    > >> >Otherwise, the library functions accessing such parameters use an
    > >> >unspecified mechanism, with undefined semantics -- in other words,
    > >> >undefined behavior. If 7.15 doesn't define the semantics of
    > >> >accessing variadic functions for library functions, which part of
    > >> >the Standard does? Unless some particular section(s) can be pointed
    > >> >to as defining those semantics, they aren't defined, and that's
    > >> >undefined behavior.
    > >>
    > >> There is no requirement that the library functions (or the compiler
    > >> for that matter) be written in C. Assuming they are restricted to
    > >> features defined in the language is unjustified.

    > >
    > >I think you missed the point. Whether library functions are written
    > >in C or in ancient Babylonian assembly language, the semantics of how
    > >their parameters are transmitted must be defined within the Standard;

    >
    > I'm pretty sure I disagree with this but I'll wait till you define
    > what you mean by semantics in this context.
    >
    > >if there is no such definition, calling a library function would be
    > >undefined behavior, no matter how it's implemented. Until someone can
    > >point out an alternative, the only candidates are regular parameter
    > >transmission for ordinary arguments, and <stdarg.h> transmission for
    > >variadic arguments. The mechanism for collecting arguments (the
    > >implementation) can be anything at all; but the semantics of what

    >
    > If the mechanism can be anything at all, it need not be related to
    > anything in stdarg.h. stdarg.h provides only one of many possible
    > mechanisms. The one that the compiler will use for code you compile.
    > It does not mean that library functions must use it.
    >
    > >parameter values correspond to which argument values, and what

    >
    > I'll agree with the correlation between arguments and parameters.
    >
    > >processing is done on those parameter values, must be defined within
    > >the Standard -- otherwise it's undefined behavior.

    >
    > Processing done on the parameters by programs coded in C (like all
    > other processing by such programs) must be defined by the standard (or
    > designated as unspecified or implementation defined, etc). Processing
    > done by other programs is obviously not covered by the standard. The
    > only requirement on a library function is that it must comply with the
    > interface specified in the standard (name, types of arguments, and
    > type and meaning of return value if any). How they do so is up the
    > implementation. A library function is free to use the tools provided
    > in stdarg.h OR NOT.


    Let me try an explanation starting from a different direction
    and see if that helps.

    Consider calling ordinary (non-library) functions. A function
    prototype, or non-prototype declaration, or function definition,
    specifies an interface for such a function; in the case of
    user-defined functions defined with an ellipsis, the interface for
    variadic parameters is defined implicitly by what calls are made to
    va_arg(), etc.

    In order to define what these interface specifications require, the
    Standard states conformance rules that specify which arguments satisfy
    the declaration or definition in each particular case. These
    conformance rules are defined in 6.5.2.2p{4,6,7,8}, and 6.9.1p{7,8,10}
    for non-variadic arguments, and in 7.15.1.1p2 for variadic arguments.

    Now consider the case of the library functions fprintf(), etc. The
    interface for fprintf() is defined in 7.19.6.1p{1-8}. But what
    defines the conformance rules? There is this sentence in 7.19.6.1p9:

    If any argument is not the correct type for the corresponding
    conversion specification, the behavior is undefined.

    Apparently the conformance rule is that an argument be "the correct
    type". What does this term mean? It isn't defined as a term in the
    Standard, so there are two possibilities: one, it stands on its own,
    so there is ambiguity about what it means; or two, it refers to a
    conformance rule stated somewhere else in the Standard. But in any
    case it must have /some/ definition (even if that definition is only
    implicit); if it has /no/ definition, then no argument could ever
    satisfy the condition, which is always undefined behavior.

    If we look at the first case (where the term "means whatver it means")
    then there isn't much more to say -- people can kind of believe
    whatever they want, and there's no way to demonstrate otherwise.
    Personally, I believe the stronger case here is the case for the
    <stdarg.h> interpretation, for two reasons: one, it's the most
    obvious reading; and two, it's more likely to be consistent with
    existing bodies of code, which rely on passing unsigned int arguments
    for %d specifiers, etc. Moreover, if what was meant was that the
    argument type be exactly the same type as those listed in the earlier
    paragraphs, then it seems likely the text would say 'the same type'
    (perhaps with a following restrictive phrase) rather than what it
    does say. But as I said, there is no absolutely convincing
    argument in this case (and people will believe whatever they
    want to believe).

    If we look at the second case (where the term refers to conformance
    rules stated elsewhere), then those rules must be defined somewhere.
    Where? Certainly the sections that define conformance rules for
    regular user-defined functions are one possibility. Unless another
    possible section can be pointed out (and it's always possible that
    there is one that I've missed), 7.15 provides the only "somewhere
    else" that this phrase might refer to.


    > It wouldn't surprise me if many library functions, such as fopen or
    > malloc, cannot be written in standard C because they must use system
    > specific features for which the language provides no tools. Once the
    > door is open, there is no reason printf can't walk through also.


    How library functions are implemented is irrelevant. The question is,
    what are the conformance rules that they must adhere to? To say this
    another way, what does it mean to satisfy an interface specification?
    The Standard must define such conformance rules, independent of any
    implementation, because in the absence of such a definition, no
    argument value could ever satisfy the conditions needed to prevent
    undefined behavior.
     
    Tim Rentsch, Feb 15, 2009
    #4
    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. Steffen Fiksdal

    void*, char*, unsigned char*, signed char*

    Steffen Fiksdal, May 8, 2005, in forum: C Programming
    Replies:
    1
    Views:
    592
    Jack Klein
    May 9, 2005
  2. whatluo

    (void) printf vs printf

    whatluo, May 26, 2005, in forum: C Programming
    Replies:
    29
    Views:
    1,256
  3. Replies:
    5
    Views:
    843
    S.Tobias
    Jul 22, 2005
  4. Replies:
    1
    Views:
    413
    Victor Bazarov
    May 23, 2007
  5. guru
    Replies:
    8
    Views:
    286
Loading...

Share This Page