Integer to "string" conversions

Discussion in 'C Programming' started by bwaichu@yahoo.com, Sep 30, 2006.

  1. Guest

    Now, I read the faq, and it suggests using sprintf. However,
    I want to all ways know where the integer finishes in the string.
    Basically, I want to:

    nbr | other data

    But the other data all ways has to start at the same place. I had
    some problems using sprintf to accomplish this requirement. Maybe
    I am overlooking something. But sprintf translates the nbr exactly
    into
    the string, so the nbr 123, would end up occupying:

    p[0] = '1'
    p[1] = '2'
    p[2] = '3'

    So as the number grew, the space taken grew.

    To solve this, I went with the solution below. But this would require
    me
    to OR back the number later. Is there a better way to do this?

    Note: I am using uint32_t to signify a 32 bit unsigned integer. This
    is implementation
    specific, but for the sake of this discussion, I need to know
    the size
    of the integer being assigned to buf ahead of time. I am also
    ignoring
    dynamically allocated arrays for this discussion as well.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    int
    main(void) {

    int i;
    uint32_t nbr;
    unsigned char buf[4];

    nbr = 0xffffffff;
    memset(buf, 0, sizeof buf);

    buf[0] = (unsigned char)(nbr >> 24) & 0xff;
    buf[1] = (unsigned char)(nbr >> 16) & 0xff;
    buf[2] = (unsigned char)(nbr >> 8) & 0xff;
    buf[3] = (unsigned char) nbr & 0xff;

    for(i = 0; i < 4; i++)
    printf("%d\n", buf);

    exit(EXIT_SUCCESS);
    }
    , Sep 30, 2006
    #1
    1. Advertising

  2. Eric Sosman Guest

    wrote:

    > Now, I read the faq, and it suggests using sprintf. However,
    > I want to all ways know where the integer finishes in the string.
    > Basically, I want to:
    >
    > nbr | other data
    >
    > But the other data all ways has to start at the same place. I had
    > some problems using sprintf to accomplish this requirement. Maybe
    > I am overlooking something. [...]


    Probably things like "%5d" or "%05d".

    --
    Eric Sosman
    lid
    Eric Sosman, Sep 30, 2006
    #2
    1. Advertising

  3. mkaras Guest

    wrote:
    > Now, I read the faq, and it suggests using sprintf. However,
    > I want to all ways know where the integer finishes in the string.
    > Basically, I want to:
    >
    > nbr | other data
    >
    > But the other data all ways has to start at the same place. I had
    > some problems using sprintf to accomplish this requirement. Maybe
    > I am overlooking something. But sprintf translates the nbr exactly
    > into
    > the string, so the nbr 123, would end up occupying:
    >
    > p[0] = '1'
    > p[1] = '2'
    > p[2] = '3'
    >
    > So as the number grew, the space taken grew.
    >
    > To solve this, I went with the solution below. But this would require
    > me
    > to OR back the number later. Is there a better way to do this?
    >
    > Note: I am using uint32_t to signify a 32 bit unsigned integer. This
    > is implementation
    > specific, but for the sake of this discussion, I need to know
    > the size
    > of the integer being assigned to buf ahead of time. I am also
    > ignoring
    > dynamically allocated arrays for this discussion as well.
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > #include <string.h>
    >
    > int
    > main(void) {
    >
    > int i;
    > uint32_t nbr;
    > unsigned char buf[4];
    >
    > nbr = 0xffffffff;
    > memset(buf, 0, sizeof buf);
    >
    > buf[0] = (unsigned char)(nbr >> 24) & 0xff;
    > buf[1] = (unsigned char)(nbr >> 16) & 0xff;
    > buf[2] = (unsigned char)(nbr >> 8) & 0xff;
    > buf[3] = (unsigned char) nbr & 0xff;
    >
    > for(i = 0; i < 4; i++)
    > printf("%d\n", buf);
    >
    > exit(EXIT_SUCCESS);
    > }


    You are making your life far far too hard.

    A) If you you used the following:

    char buf[25];
    unsigned int num = 3784;
    sprintf(buf, "%d", num);

    you could easily use strlen(buf) to figure out how long the sprintf()
    result is.

    B) Why not combine all the string formatting together into one process
    using something like:

    char buf[100];
    unsigned int num = 23405;
    unsigned int num2 = 978;
    char name[] = "Ben Hurr";
    sprintf(buf, "%10d %s - %d\n", num, name, num2);

    - mkaras
    mkaras, Sep 30, 2006
    #3
  4. pete Guest

    wrote:
    >
    > Now, I read the faq, and it suggests using sprintf. However,
    > I want to all ways know where the integer finishes in the string.
    > Basically, I want to:
    >
    > nbr | other data
    >
    > But the other data all ways has to start at the same place. I had
    > some problems using sprintf to accomplish this requirement. Maybe
    > I am overlooking something. But sprintf translates the nbr exactly
    > into
    > the string, so the nbr 123, would end up occupying:
    >
    > p[0] = '1'
    > p[1] = '2'
    > p[2] = '3'
    >


    sizeof "123" is four, not three.

    p[3] = '\0'

    --
    pete
    pete, Sep 30, 2006
    #4
  5. Guest

    mkaras wrote:

    > You are making your life far far too hard.
    >
    > A) If you you used the following:
    >
    > char buf[25];
    > unsigned int num = 3784;
    > sprintf(buf, "%d", num);
    >
    > you could easily use strlen(buf) to figure out how long the sprintf()
    > result is.


    True, but then buf grows even larger. Let me explain what I am doing.
    I am writing a file to a socket. I am working on designing the
    protocol,
    so I want to write the size of the file as well as other information
    before
    appending a portion of the file to the buffer. I need to make sure that
    the size of the file is all ways at the same place in the buffer, and I
    want to make sure the portion of the file all ways starts in the
    same place.

    Once that is done, the receiving end will know how to process the
    packet
    being received.

    At the end of the day, I am just copying between two buffers. The file
    transfer
    stuff is implementation specific -- off topic here. One side just
    creates a
    buffer and sends if over the wire. The other side writes that packet
    to a buffer
    and processes it. It still is just copying one buffer to another.

    >
    > B) Why not combine all the string formatting together into one process
    > using something like:
    >
    > char buf[100];
    > unsigned int num = 23405;
    > unsigned int num2 = 978;
    > char name[] = "Ben Hurr";
    > sprintf(buf, "%10d %s - %d\n", num, name, num2);


    I intend to write specific functions for handling the creation of the
    final buffer.
    I posted one under "more buffer" here a while ago. That one just
    appended
    characters to a buffer and resized as needed. I received great
    feedback
    for expanding that buffer by incremental pages. That solution is
    working out great.
    It lead me to look more carefully at bitwise operators.

    For the purposes of this buffer, I do not need to nul terminate, I just
    need
    to store somewhere the location of the end of the buffer as well as the
    size of
    the buffer. But I can nul terminate for the sake of maintaining c
    strings, and just overwrite
    the nul terimator with the subsequent append.
    , Oct 1, 2006
    #5
  6. CBFalconer Guest

    "" wrote:
    >
    > Now, I read the faq, and it suggests using sprintf. However,
    > I want to all ways know where the integer finishes in the string.
    > Basically, I want to:
    >
    > nbr | other data
    >
    > But the other data all ways has to start at the same place. I had
    > some problems using sprintf to accomplish this requirement. Maybe
    > I am overlooking something. But sprintf translates the nbr exactly
    > into the string, so the nbr 123, would end up occupying:
    >
    > p[0] = '1'
    > p[1] = '2'
    > p[2] = '3'
    >
    > So as the number grew, the space taken grew.
    >
    > To solve this, I went with the solution below. But this would
    > require me to OR back the number later. Is there a better way
    > to do this?
    >
    > Note: I am using uint32_t to signify a 32 bit unsigned integer.
    > This is implementation specific, but for the sake of this
    > discussion, I need to know the size of the integer being
    > assigned to buf ahead of time. I am also ignoring dynamically
    > allocated arrays for this discussion as well.
    >
    > #include <stdio.h>
    > #include <stdlib.h>

    /* #include <string.h>
    */
    > int
    > main(void) {
    > int i;

    unsigned long nbr;
    > unsigned char buf[4];
    >
    > nbr = 0xff100401;

    /* memset(buf, 0, sizeof buf); */
    >
    > buf[0] = (unsigned char)(nbr >> 24) & 0xff;
    > buf[1] = (unsigned char)(nbr >> 16) & 0xff;
    > buf[2] = (unsigned char)(nbr >> 8) & 0xff;
    > buf[3] = (unsigned char) nbr & 0xff;
    >

    for (i = 0; i < 4; i++) printf("%03d ", buf);
    putchar('\n');
    >
    > exit(EXIT_SUCCESS);
    > }


    Does the above do what you want? Note changes.

    --
    Some useful references about C:
    <http://www.ungerhu.com/jxh/clc.welcome.txt>
    <http://www.eskimo.com/~scs/C-faq/top.html>
    <http://benpfaff.org/writings/clc/off-topic.html>
    <http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
    <http://www.dinkumware.com/refxc.html> (C-library}
    <http://gcc.gnu.org/onlinedocs/> (GNU docs)
    <http://clc-wiki.net> (C-info)
    CBFalconer, Oct 1, 2006
    #6
  7. Guest

    CBFalconer wrote:
    > > #include <stdio.h>
    > > #include <stdlib.h>

    > /* #include <string.h>
    > */
    > > int
    > > main(void) {
    > > int i;

    > unsigned long nbr;
    > > unsigned char buf[4];
    > >
    > > nbr = 0xff100401;

    > /* memset(buf, 0, sizeof buf); */
    > >
    > > buf[0] = (unsigned char)(nbr >> 24) & 0xff;
    > > buf[1] = (unsigned char)(nbr >> 16) & 0xff;
    > > buf[2] = (unsigned char)(nbr >> 8) & 0xff;
    > > buf[3] = (unsigned char) nbr & 0xff;
    > >

    > for (i = 0; i < 4; i++) printf("%03d ", buf);
    > putchar('\n');
    > >
    > > exit(EXIT_SUCCESS);
    > > }

    >
    > Does the above do what you want? Note changes.


    Yes. Here's taking those changes to the next step:

    int
    main(void) {

    int i;
    unsigned long nbr, nbr2;
    unsigned char buf[4];

    nbr = 0xff100401;

    printf("%lu\n", nbr);

    buf[0] = (unsigned char)(nbr >> 24) & 0xff;
    buf[1] = (unsigned char)(nbr >> 16) & 0xff;
    buf[2] = (unsigned char)(nbr >> 8) & 0xff;
    buf[3] = (unsigned char) nbr & 0xff;

    for(i = 0; i < 4; i++)
    printf("%03d", buf);
    putchar('\n');

    nbr2 = (unsigned long)buf[0] << 24;
    nbr2 |= (unsigned long)buf[1] << 16;
    nbr2 |= (unsigned long)buf[2] << 8;
    nbr2 |= (unsigned long)buf[3];

    printf("%lu\n", nbr2);

    exit(EXIT_SUCCESS);
    }

    I am able to "save" the integer to the buffer and extract it later.
    You removed my
    memset because I was immediately assigning the array after it, right?
    unsigned
    long is 32 bit, so you backed away my implementation specific type. But
    I don't
    quite get your printf change. It guarantees that each item printed
    from the array
    buf is 3 characters wide and will lead with a zero if needed. Why that
    change?

    Thanks!
    , Oct 1, 2006
    #7
  8. wrote:
    > True, but then buf grows even larger. Let me explain what I am doing.
    > I am writing a file to a socket. I am working on designing the
    > protocol,
    > so I want to write the size of the file as well as other information
    > before
    > appending a portion of the file to the buffer. I need to make sure that
    > the size of the file is all ways at the same place in the buffer, and I
    > want to make sure the portion of the file all ways starts in the
    > same place.
    >
    > Once that is done, the receiving end will know how to process the
    > packet
    > being received.


    You are still making this incredibly too hard for what is normally done. By
    hard I mean you shouldn't be converting integers to strings, etc. just to
    transmit it over a socket. You're working with sockets, so we're already out
    of comp.lang.c land, and I'm adding comp.unix.programmer here. As a result of
    working with sockets, you SHOULD have the standard repertoire of functions
    available. If you want to transmit the size of a file, previous to the file,
    aka LV, or extended more, TLV (type-length-value), you do just that. However,
    you design things ahead of time such that both sides know what protocol
    they're speaking, and you always transmit any single object larger than a
    byte in network byte order. This applies to shorts, ints, longs, etc. It does
    not apply to streams of byte data. Before you even get into this territory,
    it's pretty much required that you pick up a copy of W. Richard Stevens: Unix
    Network Programming, Volume 1. Without it, you're going to make a lot of
    novice mistakes.

    In your particular example, you want to send size first, most likely as a
    network byte order uint_32t and then the stream of bytes representing the
    file. Extremely basic protocol, essentially:

    /*
    * all code below not entirely comp.lang.c safe
    */

    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <sys/uio.h>

    ssize_t file_send(int, char *, size_t);
    ssize_t file_recv(int, char *, size_t);

    ssize_t file_send(int s, char *buf, size_t sz)
    {
    struct iovec packet[2];
    ssize_t bw;
    uint32_t nbo_sz;

    /* host to network long, look it up and use it, or else */
    nbo_sz = htonl(sz);
    packet[0].iov_len = sizeof(nbo_sz);
    packet[0].iov_base = &nbo_sz;
    packet[1].iov_len = sz;
    packet[1].iov_base = buf;

    /*
    * naive, don't do as one call and call it a day, and don't do it as
    * blocking. this is entirely for simple contrived example.
    * read: W. Richard Stevens: UNPv1
    */
    if ((bw = writev(s, packet, 2)) == -1) {
    perror("writev");
    return -1;
    }

    return bw;
    }

    ssize_t file_recv(int s, char *buf, size_t sz)
    {
    struct iovec packet[2];
    ssize_t br, brt = 0;
    uint32_t nbo_sz;

    /*
    * in this recv example, one doesn't necessarily need to use iovecs,
    * but it's a good idea as you may end up sending more than just size
    * initially.
    */
    packet[0].iov_len = sizeof(nbo_sz);
    packet[0].iov_base = &nbo_sz;

    /*
    * naive, don't do as one call and call it a day, and don't do it as
    * blocking. this is entirely for simple contrived example.
    * read: W. Richard Stevens: UNPv1
    */
    if ((br = readv(s, packet, 1)) == -1) {
    perror("readv");
    return -1;
    }
    brt += br;

    /* network to host long, look it up and use it, or else */
    nbo_sz = ntohl(nbo_sz);

    /*
    * better handle nbo_sz > sz, and handle it appropriately either
    * through a callback to handle the remaining bytes, realloc, etc
    * or some other form of unexpected case handling or do it
    * after the intial sz-max read.
    */
    packet[0].iov_len = nbo_sz > sz ? sz : nbo_sz; /* example only */
    packet[0].iov_base = buf;

    /*
    * naive, don't do as one call and call it a day, and don't do it as
    * blocking. this is entirely for simple contrived example.
    * read: W. Richard Stevens: UNPv1
    */
    if ((br = readv(s, packet, 1)) == -1) {
    perror("readv");
    return -1;
    }
    brt += br;

    /*
    * possibly handle nbo_sz > sz here by calling a user supplied callback
    * to realloc or store elsewhere or some other form of unexpected case
    * handling. either way, plan for it - as it will happen.
    */

    return brt;
    }
    Christopher Layne, Oct 1, 2006
    #8
  9. CBFalconer Guest

    "" wrote:
    > CBFalconer wrote:
    >

    .... snip ...
    >
    > for (i = 0; i < 4; i++)
    > printf("%03d", buf);
    > putchar('\n');
    >

    .... snip ...
    >
    > I don't quite get your printf change. It guarantees that each
    > item printed from the array buf is 3 characters wide and will
    > lead with a zero if needed. Why that change?


    I thought you were complaining that the field used varied with the
    value. If you don't want the leading zeroes, remove the '0'.

    --
    Some informative links:
    <news:news.announce.newusers
    <http://www.geocities.com/nnqweb/>
    <http://www.catb.org/~esr/faqs/smart-questions.html>
    <http://www.caliburn.nl/topposting.html>
    <http://www.netmeister.org/news/learn2quote.html>
    <http://cfaj.freeshell.org/google/>
    CBFalconer, Oct 1, 2006
    #9
  10. CBFalconer wrote:

    > I thought you were complaining that the field used varied with the
    > value. If you don't want the leading zeroes, remove the '0'.


    As far as I could tell, he was looking for a way of encoding "size" in a fixed
    length method that would be network-portable. snprintf() could be used for
    that, in a rather bizarre, inefficient, and roundabout way.
    Christopher Layne, Oct 1, 2006
    #10
  11. Guest

    Christopher Layne wrote:
    > CBFalconer wrote:
    >
    > > I thought you were complaining that the field used varied with the
    > > value. If you don't want the leading zeroes, remove the '0'.

    >
    > As far as I could tell, he was looking for a way of encoding "size" in a fixed
    > length method that would be network-portable. snprintf() could be used for
    > that, in a rather bizarre, inefficient, and roundabout way.


    True. But I wanted to leave the network related items off this
    newsgroup. And
    I have read Stevens' book.
    , Oct 1, 2006
    #11
  12. wrote:
    > True. But I wanted to leave the network related items off this
    > newsgroup. And
    > I have read Stevens' book.


    Understandable. But why even consider such a ridiculous way of encoding when
    the tried and true method is both more efficient, lower overhead, and more
    natural?
    Christopher Layne, Oct 2, 2006
    #12
  13. Guest

    Christopher Layne wrote:

    > Understandable. But why even consider such a ridiculous way of encoding when
    > the tried and true method is both more efficient, lower overhead, and more
    > natural?


    What's the tried and true method? I did not get a lot out of Stevens'
    when it comes
    to protocol design. I saw a lot of different approaches to the
    blocking problem.
    But I never considered using writev or readv to build a protocol. I
    figured I would
    just write the protocol stuff to the front of the buffer and read it on
    the other end
    after doing any network translation as needed.

    So you would build all your protocol information into struct iovec?
    Basically, I was
    thinking of sending only a few items: crc or sha1, file size, and file.
    I was going
    to buffer this out at the page size or twice the page size. My
    approach to handling
    the blocking problem was to use pthreads. Once this worked, my next
    step was
    to use ssl.

    Of course, all of this is off topic here.

    Cheers!
    , Oct 2, 2006
    #13
  14. wrote:
    > So you would build all your protocol information into struct iovec?


    I mainly use iovec's because they are natural for this purpose and also
    because of the win/win of not having to marshal data into a temporary buffer
    (don't even think of sending a struct over the network either) and/or call
    read() more than once. That's the main goal of readv()/writev().

    > Basically, I was
    > thinking of sending only a few items: crc or sha1, file size, and file.
    > I was going
    > to buffer this out at the page size or twice the page size.


    No need to do this really, that is page size buffering, etc. - atleast for the
    transmission side. What one typically does is handle things via typical
    realloc() and keep that larger buffer around for the life of the program or
    downsize it to an average size seen, bordering a page boundary. As far as the
    protocol itself, a basic protocol will revolve around TLV encoding + 1 main
    header and possibly a trailer (although unlikely). Keep things small but not
    so small there is no room for future expansion - and possibly consider a
    version byte, or short.

    > My
    > approach to handling
    > the blocking problem was to use pthreads. Once this worked, my next
    > step was
    > to use ssl.


    Let me give you some guidance here, as I have direct experience with it,
    including pthreads + socket programming. Attempting to use threads (let's say
    thread per connection) as a method of getting around blocking is going to
    result in eventual pain - and not because of threading - just that one cannot
    100% trust select(). The best way to get around blocking issues is to do just
    that - write non-blocking handlers. If you need example code for all basic
    socket routines, let me know - but I highly recommend writing your own first
    so you can make the common mistakes and figure out they were made. It's
    really not total rocket science, but don't make any assumptions. This is
    where UNPv1 will come in extremely valuable. For a while I thought my
    readv()/writev() routines would never return a partial read or partial write
    space available error. It only took one serious stream of data above the MTU
    to prove this wrong. This particular situation was only a tad more difficult
    than normal as prior-documentation for it wasn't really out there on the net
    (for readv()/writev() specifically). Like I said, just don't even bother with
    blocking mode.

    > Of course, all of this is off topic here.


    Yep, comp.unix.programmer. Followed up.
    Christopher Layne, Oct 2, 2006
    #14
    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. Kai Koehne
    Replies:
    10
    Views:
    1,150
    Patricia Shanahan
    May 15, 2006
  2. Replies:
    10
    Views:
    699
    Jasen Betts
    Aug 5, 2005
  3. Replies:
    17
    Views:
    416
  4. Replies:
    11
    Views:
    490
    Richard Bos
    May 8, 2008
  5. Randy Kramer
    Replies:
    12
    Views:
    360
    Robert Klemme
    Oct 25, 2007
Loading...

Share This Page