28

I have a buffer which I receive through a serial port. When I receive a certain character, I know a full line has arrived, and I want to print it with printf method. But each line has a different length value, and when I just go with:

printf("%s", buffer);

I'm printing the line plus additional chars belonging to the former line (if it was longer than the current one).

I read here that it is possible, at least in C++, to tell how much chars you want to read given a %s, but it has no examples and I don't know how to do it in C. Any help?

I think I have three solutions:

  • printing char by char with a for loop
  • using the termination character
  • or using .*

QUESTION IS: Which one is faster? Because I'm working on a microchip PIC and I want it to happen as fast as possible

jww
  • 97,681
  • 90
  • 411
  • 885
Roman Rdgz
  • 12,836
  • 41
  • 131
  • 207
  • 2
    When you've received that *"certain character"* and have appended it to `buffer`, append a null character (`\0`) as well. This "tells" `sprintf()` when to stop printing characters. – Linus Kleen Nov 17 '11 at 16:31

4 Answers4

62

You can either add a null character after your termination character, and your printf will work, or you can add a '.*' in your printf statement and provide the length

printf("%.*s",len,buf);

In C++ you would probably use the std::string and the std::cout instead, like this:

std::cout << std::string(buf,len);

If all you want is the fastest speed and no formatting -- then use

fwrite(buf,1,len,stdout);
Soren
  • 14,402
  • 4
  • 41
  • 67
  • Perfect. So I have three solutions: printing char by char with a for loop, using the termination character, or using .* QUESTION IS: which one is faster? Because I'm working on a microchip PIC and I want it to happen fast – Roman Rdgz Nov 17 '11 at 16:42
  • @RomanRdgz: my guesses: `fwrite` or null-termination+`fputs` should be the fastest, followed by null-termination+`printf` (could be slower because it may have to parse the format string, unless the compiler is very smart) then `printf` with `.*` (surely needs to parse the format string) and last printing char by char (probably the slowest, because of all the function calls - that however could be inlined). – Matteo Italia Nov 17 '11 at 16:47
  • Also, your C++ version is quite inefficient, you are allocating/deallocating stuff on the heap (constructing an instance of `std::string`) when a simple call to `cout.write` would be enough. Not that it would matter once in a while on a normal machine, but with very limited resources or in a tight loop it may be noticeable. – Matteo Italia Nov 17 '11 at 16:48
  • I'm using CCS compiler, and I don't think it has cout.write. That's why I'm using fputs or printf. Thanks for your info @Matteo Italia – Roman Rdgz Nov 17 '11 at 16:50
  • @RomanRdgz: if you have `cout` you'll surely have `cout.write`, anyhow that was just a comment about the C++ solution of @Soren, for C solutions I already wrote my answer :) . – Matteo Italia Nov 17 '11 at 16:51
  • If all you want is the fastest speed and no formatting -- then use `fwrite(buf,1,len,stdout)` – Soren Nov 17 '11 at 16:52
  • PIC - ugh! Anyway, since you know you are at the end of the line, shove a null in and avoid the printf having to count, (if only to keep the format parsing to a minimum), - that's probably fastest. What are you printing to anyway? – Martin James Nov 17 '11 at 16:55
  • I am printting to a serial port, with fprintf/fputs/fputc – Roman Rdgz Nov 17 '11 at 16:57
37

The string you have is not null-terminated, so, printf (and any other C string function) cannot determine its length, thus it will continue to write the characters it finds there until it stumbles upon a null character that happens to be there.

To solve your problem you can either:

  • use fwrite over stdout:

    fwrite(buffer, buffer_length, 1, stdout);
    

    This works because fwrite is not thought for printing just strings, but any kind of data, so it doesn't look for a terminating null character, but accepts the length of the data to be written as a parameter;

  • null-terminate your buffer manually before printing:

    buffer[buffer_length]=0;
    printf("%s", buffer); /* or, slightly more efficient: fputs(buffer, stdout); */
    

    This could be a better idea if you have to do any other string processing over buffer, that will now be null-terminated and so manageable by normal C string processing functions.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 1
    I am surprised that answers to duplicates of this SO question do not include this method, but only suggest `for` loops... – Alex Jul 05 '17 at 13:45
3

Once you've identified the end of the line, you must append a '\0' character to the end of the buffer before sending it to printf.

Michael Price
  • 8,088
  • 1
  • 17
  • 24
3

You can put a NUL (0x0) in the buffer after receiving the last character.

buffer[i] = 0;

Gowtham
  • 1,465
  • 1
  • 15
  • 26