How to Do Printf in R

How to do printf in r?

printf <- function(...) invisible(print(sprintf(...)))

The outer invisible call may be unnecessary, I'm not 100% clear on how that works.

Is it possible to grab/scrape the .Call() output of C printf() within R (or with Rprintf())?

So, the issue here is printf negates R's built collection mechanisms for output. In particular, there is no C-level 'stdout' file stream and, thus, no output to collect in either Rgui or RStudio. For details, please see Section 6.5 Printing
of Writing R Extensions

Two possible solutions:

  1. Define a macro that sets printf to direct into Rprintf and include the #define STRICT_R_HEADERS to avoid errors.
  2. Switch instances of printf to Rprintf in the offending code.

From here, the capture can be passed off to either capture.output(), which directly assigns output to a variable, or sink(), which redirects output to a file whose contents must then be read back in using readLines(). The latter makes it possible to have a clear enclose over multiple lines of code to capture output while the prior is focused on securing output present from an inputted expression.

Option 1

For the first iteration, just define a header that includes the custom define and then include the third party library, e.g.

my_code.h

#ifndef MY_CODE_H
#define MY_CODE_H
#include <R.h>
// this load R_ext/Print.h.

// #include <YOUR_LIBRARY.h>

// Define strict headers
#define STRICT_R_HEADERS
// Map printf to Rprintf
#define printf Rprintf
#endif

toad.c

#include <R.h>
#include <Rdefines.h>
#include "my_code.h"

SEXP helloA1() {
printf("Hello World!\n");
return(R_NilValue);
}

toad_example.R

system("R CMD SHLIB ~/Desktop/toad.c")
dyn.load("~/Desktop/toad.so")

helloA1 <- function() {
result <- .Call("helloA1")
}

# Gregor's suggestion
captured_data = capture.output(helloA1())

# Using sink around multiple function calls to redirect output
# to a single file
sink("sink-examp.txt")
helloA1()
sink()

input_data = readLines("sink-examp.txt")

all.equal(input_data, captured_data)
# [1] TRUE

I've implemented this approach in an R package that can be found here:

https://github.com/coatless/printf2Rprintf

Option 2

This option manually redefines the printf functions.

toad.c

#include <R.h>
#include <Rdefines.h>
SEXP helloA1() {
Rprintf("Hello World!\n"); // manually changed
return(R_NilValue);
}

toad_example.R

system("R CMD SHLIB ~/Desktop/toad.c")
dyn.load("~/Desktop/toad.so")

helloA1 <- function() {
result <- .Call("helloA1")
}

# Gregor's suggestion
captured_data = capture.output(helloA1())

# Using sink around multiple function calls to redirect output
# to a single file
sink("sink-examp.txt")
helloA1()
sink()

input_data = readLines("sink-examp.txt")

all.equal(input_data, captured_data)
# [1] TRUE

how to print a variable number of arguments in r?

The doc is right. In first case, do.call(sprintf, c(list("%s %s"), vec)) is equal to:

sprintf("%s %s", "a","b","c","d")

The fmt string "%s %s" requires two vectors while you provided four and the last two ("c", "d") were not used for printing.

The second case is similar. do.call(sprintf, c(fmt = base_string, as.list(v1))) is equal to:

sprintf(fmt = "%s, %s, %s", "foo", "bar", "baz","foo", "bar", "baz")

Three variables were to be printed based on fmt but you provided six.


Then, what does "recycled" in the doc mean?

and I guess you might misunderstand it. It means when the formating string and vectors are of different lengths, the short er ones will be recycled to the longest one. An example:

> sprintf(c('%s %s', '%s, %s'), c('a', 'b', 'c'), 1:6)
[1] "a 1" "b, 2" "c 3" "a, 4" "b 5" "c, 6"

How to print variable number of arguments: You can try paste:

> sprintf(paste0(vec, collapse = ' '))
[1] "a b c d"
> sprintf(paste0(v1, collapse = ', '))
[1] "foo, bar, baz, foo, bar, baz"

Printing newlines with print() in R

An alternative to cat() is writeLines():

> writeLines("File not supplied.\nUsage: ./program F=filename")
File not supplied.
Usage: ./program F=filename
>

An advantage is that you don't have to remember to append a "\n" to the string passed to cat() to get a newline after your message. E.g. compare the above to the same cat() output:

> cat("File not supplied.\nUsage: ./program F=filename")
File not supplied.
Usage: ./program F=filename>

and

> cat("File not supplied.\nUsage: ./program F=filename","\n")
File not supplied.
Usage: ./program F=filename
>

The reason print() doesn't do what you want is that print() shows you a version of the object from the R level - in this case it is a character string. You need to use other functions like cat() and writeLines() to display the string. I say "a version" because precision may be reduced in printed numerics, and the printed object may be augmented with extra information, for example.

Need help understanding how \n, \b, and \r will render printf output

Let's take it one step at a time:

<new line>ab<backspace>si<carriage return>ha

First, handle the backspace. Note that even though it is "non-erase", the next character to be output would overwrite what was backspaced over:

<new line>asi<carriage return>ha

Now, a carriage return means to go back to the beginning of the line. So the "ha" overwrites the "as" in "asi:

<new line>hai

Now, the cursor is currently sitting on the i, so the next character to be output would overwrite i.

\r in C stops output before it

The statement printf("one") does not immediately print "one" to the terminal, but it writes the string to the standard output stream (stdout) - which is usually buffered. Only when this stream is flushed, do its contents get printed to the terminal. Usually, this happens whenever a newline is printed or when the program exits, among other conditions.

The output stream can be forced to flush by calling fflush(stdout), which produces the desired result:

#include <stdio.h>
#include <unistd.h>

int main(void) {
printf("one");
fflush(stdout); // Line added
sleep(1);
printf("\r");
printf("two");
return 0;
}

See fflush for more information. The buffering mode of a stream can be set using the setvbuf function.

Also, note that the usual main signature, when using no parameters, is int main(void).

Acknowledgements: Thanks to Andreas Wenzel for a correction and the setvbuf addition.

R - do I need to add explicit new line character with print()?

The nature of R means that you're never going to have a newline in a character vector when you simply print it out.

> print("hello\nworld\n")
[1] "hello\nworld\n"

That is, the newlines are in the string, they just don't get printed as new lines. However, you can use other functions if you want to print them, such as cat:

> cat("hello\nworld\n")
hello
world


Related Topics



Leave a reply



Submit