strange warning

Discussion in 'C++' started by asdf, Jul 10, 2006.

  1. asdf

    asdf Guest

    I got a warning from the following statement:

    fprintf(point_file, "CONTOUR\nCLOSE\n%d\n", curve.size());

    warning: format '%d' expects type 'int', but argument 3 has type
    'size_t'

    should I change the coding to

    fprintf(point_file, "CONTOUR\nCLOSE\n%u\n", curve.size());

    ?

    Thanks all.
     
    asdf, Jul 10, 2006
    #1
    1. Advertisements

  2. It could be that you need %Lu if sizeof(size_t) > sizeof(int) on
    your system. Also, see the documentation for your compiler about
    what format string to use to print out 'size_t'.

    V
     
    Victor Bazarov, Jul 10, 2006
    #2
    1. Advertisements

  3. You should explicitly cast the return value of 'curve.size()' to some built-in
    integral type that is sufficiently large to hold the value, and then use the
    format specifier for that type. For example

    fprintf(point_file, "CONTOUR\nCLOSE\n%lu\n", (unsigned long) curve.size());

    Your platform might also provide an implementation-specific format specifier for
    printing 'size_t'. So you might decide to use that instead (assuming that return
    type of 'size_t' is a part of the interface specification of that 'size()' method).
     
    Andrey Tarasevich, Jul 11, 2006
    #3
  4. asdf

    Ian Collins Guest

    Isn't that rather dangerous? If the return type of curve.size() were to
    change, the cast would mask the warning.

    Better to find and use the correct format specifier and count your self
    lucky your compiler is kind enough to issue that diagnostic.
     
    Ian Collins, Jul 11, 2006
    #4
  5. asdf

    Old Wolf Guest

    Note that there is no correct specifier for 'size_t' in C++
    (C99 does have one).

    If you are suggesting to not cast curve.size() but use a
    specifier such as %lu, then what happens if you port to
    a system where size_t is different? Silent undefined behaviour.

    IMHO it is best to have an implementation-defined result
    or a compile error, as Andrey's case will give if size() is
    changed to return something else, instead of undefined
    behaviour.
     
    Old Wolf, Jul 11, 2006
    #5
  6. asdf

    Jerry Coffin Guest

    [ ... ]
    TR1 for the C++ library includes all of inttypes.h, stdint.h, etc.

    Since we're using C++, why not use an iostream that already knows how
    to deal with size_t?
     
    Jerry Coffin, Jul 11, 2006
    #6
  7. asdf

    Old Wolf Guest

    The OP has to write to a FILE* .

    He could write the size_t with a stringstream and then write
    the string to the FILE*, I suppose.
     
    Old Wolf, Jul 12, 2006
    #7
  8. asdf

    Jim Langston Guest

    You are most likely using a microsoft compiler. Although size_t is
    currently defined as an unsigned int, when you move to a 64 bit compiler it
    would change it's size (most likely unsigned long long int or such).

    Just about anywhere you use size_t you'll get a warning unless you are
    assigning a size_t var to a size_t var.

    In your particular case, there is one way to make it safer, although you'll
    still get a warning.

    std::stringstream ConvStream;
    ConvStream << "CONTOUR\nCLOSE\n" << curve.size() << "\n";
    fprintf(point_file, ConvStream.str());

    The reason this is safer is that when you do switch to a 64 bit compiler
    this code will still work without any changes. Your existing code would
    have to change the %d to %ld or something, and size_t is unsigned anyway.

    Personally, I got tired of _64 bit warnings and disabled them in my compiler
    with a project setting.
     
    Jim Langston, Jul 12, 2006
    #8
  9. asdf

    Old Wolf Guest

    There would be no warning for that code
    fprintf(point_file, ConvStream.str().c_str());

    or in fact I would prefer

    fprintf(point_file, "%s", ConvStream.str().c_str());
    Worry about it when the time comes, eh?
     
    Old Wolf, Jul 13, 2006
    #9
  10. asdf

    Jim Langston Guest

    It gave me a warning in MS VC++ .net 2003
    Well, I was looking at all the warnings, the warnings I was getting was
    about storing a SOCKET in an unsigned int which was being used for an ID in
    client server. If and when I went to a 64 bit system I would turn warnings
    back on, and just change the ID to unsigned long int or whatever it is they
    then required for a 64 bit int. Absolutely nothing I can do about it now,
    so what good are the warnings?
     
    Jim Langston, Jul 13, 2006
    #10
  11. asdf

    Old Wolf Guest

    What is the warning?
     
    Old Wolf, Jul 13, 2006
    #11
  12. asdf

    Jim Langston Guest

    size_t Value = 10;

    std::stringstream Stream;
    Stream << Value;

    c:\Source\working\console\console.cpp(11) : warning C4267: 'argument' :
    conversion from 'size_t' to 'unsigned int', possible loss of data
     
    Jim Langston, Jul 14, 2006
    #12
  13. asdf

    Old Wolf Guest

    Ok. I thought there was a version of std::eek:stream::eek:perator<<
    taking a size_t, but in fact there isn't.

    I'm not sure what you would do with a size_t that's bigger than
    an unsigned long (or if that is even possible).
     
    Old Wolf, Jul 14, 2006
    #13
  14. asdf

    Jim Langston Guest

    Well, that's the thing. If this code was switched to a 64 bit system, it
    would still work as expected, since at that time they would add a 64 bit
    unsigned int to ostream.

    The problem comes in when you attempt to store the value in some way, such
    as into an unsigned int, that when you switch to a 64 bit compiler it will
    break unless you change the unsigned int to a 64 bit int. Using
    stringstream, however, it's being converted but not stored.
     
    Jim Langston, Jul 14, 2006
    #14
  15. asdf

    peter koch Guest

    There surely is - look at my other reply.

    /Peter
     
    peter koch, Jul 14, 2006
    #15
  16. asdf

    peter koch Guest

    This is just a warning from the Microsoft Compiler - and only one that
    warns about a portability problem (when porting to 64-bit code).
    Furthermore, these warnings are quite unreliable and should not
    normally be on. As Microsofts own documentation states:

    In this situation, C4267 is caused by a limitation in /Wp64 warnings.
    On x86, std::cout<<range_index resolves to the overload of operator<<
    that accepts an unsigned int, since size_t is an unsigned int on Win32.
    C4267 occurs because you passed a size_t as an unsigned int argument,
    which would cause truncation on Win64 where size_t is 64-bit, but
    unsigned int is still 32-bit. This can be ignored because if you
    compiled for Win64, std::cout<<range_index would resolve to the
    overload of operator<< that accepts an unsigned __int64, since that's
    what type size_t is on Win64. The 32-bit compiler doesn't notice, so it
    warns.

    /Peter
     
    peter koch, Jul 14, 2006
    #16
  17. asdf

    Old Wolf Guest

    According to the 1998 version of the standard, the only overloads
    for operator<< are: charT, char, signed char, unsigned char,
    complex<T>, bool, short, unsigned short, int, unsigned int,
    long, unsigned long, float, double, long double, and some pointers.

    The standard doesn't appear to say anything about the type
    of size_t; in fact, as far as I can see, it doesn't even say that
    it has to be an integral type.

    17.4.4.7 says:
    Unless explicitly stated otherwise, types with distinct names are
    distinct types.174)

    and the footnote is:
    174) An implicit exception to this rule are types described as
    synonyms for basic integral types, such as size_t (18.1) and
    streamoff (27.4.1).

    Although 27.4.1 defines streamoff as being a synonym for an
    integral type, 18.1 (or any other section for that matter)
    does not describe size_t as being a synonym for anything.
     
    Old Wolf, Jul 16, 2006
    #17
  18. asdf

    Kai-Uwe Bux Guest

    The C++ standard says that std::size_t is defined in <cstddef>. Also [18/3]
    says that <cstddef> provides the same contents as the C header stddef.h.
    Thus, the C++ standard refers to the C standard here. I have no copy of the
    C standard, but the draft version provides in [7.17] that size_t is "the
    unsigned integer type of the result of the sizeof operator".


    Best

    Kai-Uwe Bux
     
    Kai-Uwe Bux, Jul 17, 2006
    #18
  19. asdf

    Jerry Coffin Guest

    [ ... ]
    size_t is defined in cstddef/stddef.h. Section 18.1/3 describes
    cstddef as: "The contents are the same as the Standard C library
    header <stddef.h> with the following changes:" (and none of the
    changes applies to size_t, only to offsetof and NULL).

    In the C90 standard, section 7.1.6 says size_t is "the unsigned
    integral type of the result of the sizeof operator;"

    So, size_t must be a synonym for one of the unsigned integral types
    (unsigned char, unsigned short, unsigned int, unsigned long or
    possibly "plain" char, if it happens to be unsigned). In C99 and
    almost certainly the next version of C++, unsigned long long will be
    possible as well, but that type doesn't exist in C++ as it's
    currently defined (though many compilers support it anyway).
     
    Jerry Coffin, Jul 17, 2006
    #19
  20. asdf

    Old Wolf Guest

    In C99, size_t does not have to be a synonym for an
    integral type (although it does in C90, as you point out).

    Another can of worms for the C++ standards committee :)
     
    Old Wolf, Jul 17, 2006
    #20
    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.