30

When you are printing a tab character to the standard output using printf in C, it outputs some space which is apparently 4 characters in length.

printf("\t");

Is there a way by which I can control the tab width in the above case?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
liv2hak
  • 14,472
  • 53
  • 157
  • 270

3 Answers3

59

That's something controlled by your terminal, not by printf.

printf simply sends a \t to the output stream (which can be a tty, a file, etc.). It doesn't send a number of spaces.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cnicutar
  • 178,505
  • 25
  • 365
  • 392
31

A tab is a tab. How many spaces it consumes is a display issue, and depends on the settings of your shell.

If you want to control the width of your data, then you could use the width sub-specifiers in the printf format string. For example,

printf("%5d", 2);

It's not a complete solution (if the value is longer than five characters, it will not be truncated), but it might be OK for your needs.

If you want complete control, you'll probably have to implement it yourself.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • 4
    Actually for strings you can get truncation: `printf("%5.5s","abcdefg");` will output "abcde". And if you always want the output left-aligned for cases where the string is less than 5 characters, use `"%-5.5s"` – proFromDover Jul 11 '11 at 09:53
  • @proFromDover : if you can limit yourself to strings, that's ok, yes. – Sander De Dycker Jul 11 '11 at 10:22
0

If your terminal supports proper ANSI escape sequences, there are escape sequences to set tab stops to any location on the screen. The escape sequence ESC [ 3 g clears all tab stops, the escape sequence ESC H sets the tab stop at a specific location.

Below is an POSIX example C program that provides a function that set's tab stops to the specified count of spaces. First all existing tabs are removed, then spaces are printed and in proper locations the tab stop is set. Then the cursor is rewind back to the start of the line.

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>

int writestr(int fd, const char *s) {
    return write(fd, s, strlen(s)) == (ssize_t)strlen(s) ? 0 : -1;
}

int set_tab_stops(unsigned distance) {
    assert(distance > 0);
    // Using stdout here, stderr would be more reliable. 
    FILE *file = stdout;
    const int fd = fileno(file);
    // We have to flush stdout in order to use fileno.
    fflush(file);
    // Get terminal width.
    // https://stackoverflow.com/questions/1022957/getting-terminal-width-in-c
    struct winsize w = {0};
    if (ioctl(fd, TIOCGWINSZ, &w) < 0) return -__LINE__;
    const unsigned cols = w.ws_col;
    // Remove all current tab stops.
    if (writestr(fd, "\033[3g") < 0) return -__LINE__;
    // Do horicontal tabs each distance spaces.
    for (unsigned i = 0; i < cols; ++i) {
        if (i % distance == distance - 1) {
            if (writestr(fd, "\033H") < 0) return -__LINE__;
        }
        if (writestr(fd, " ") < 0) return -__LINE__;
    }
    // Clear the line and return to beginning of the line.
    if (writestr(fd, "\033[1K\033[G") < 0) return -__LINE__;
    return 0;
}

int main() {
    set_tab_stops(10);
    printf("1\t2\t3\t4\n");
    set_tab_stops(5);
    printf("1\t2\t3\t4\n");
}

With xfce4-terminal the program outputs:

1        2         3         4
1   2    3    4
KamilCuk
  • 120,984
  • 8
  • 59
  • 111