2

I did a function who prints with write an unsigned int :

ssize_t     putc_fdr(char c, int fd)
{
    return (write(fd, &c, sizeof(char)));
}

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
        return (i != 0 ? putuint_fdr(i / 10, fd) + putc_fdr(i % 10 + '0', fd) : 0);
}

But it don't work for i = 0 because the function don't print anything. And if I replace ': 0' with ': putc_fdr('0', fd)' it will not work because if i > 10, at the end of the recursion an additionnal '0' will always be printed. (logic.) But how to print this 0 only if the beginning i is 0 ?

tfontain
  • 66
  • 12
  • 1
    The evaluation of the operands to a `+` is in an unspecified order. Your number is as likely to be printed correctly as it is to be printed in reverse. – StoryTeller - Unslander Monica Mar 14 '17 at 19:42
  • If = 0 it will return 0, because that's what you coded it to do. To be more clear, the expression (i != 0 ? X : Y) will always return Y. – NomeQueEuLembro Mar 14 '17 at 19:45
  • Possible duplicate of [Why are these constructs (using ++) undefined behavior?](http://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – too honest for this site Mar 14 '17 at 19:46
  • 1
    [Binary `+` is unsequenced](http://stackoverflow.com/documentation/c/1275/sequence-points/4180/unsequenced-expressions#t=201703141951412249929). – jxh Mar 14 '17 at 19:52

3 Answers3

4

Rather than stopping at zero, stop when you reached a single digit.

And you should fix the sequencing problem (thus ensuring a correct printing order) by ditching the ?: operator, and allowing your function a default behavior with less repetition:

ssize_t     putuint_fdr(uintmax_t i, int fd) {
        ssize_t ret1 = 0;

        if(i / 10 != 0)
          ret1 = putuint_fdr(i / 10, fd);

        if (ret1 < 0) 
          return ret1; 

        ssize_t ret2 = putc_fdr(i % 10, fd);

        if (ret2 < 0)
          return ret2;

        return ret1 + ret2;
}
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

Consider what your expression do:

(i != 0 ? putuint_fdr(i / 10, fd) + putc_fdr(i % 10 + '0', fd) : 0);

First, it checks for the condition i != 0. Then if condition is true it will:

  • Recursively call itself with the statement putuint_fdr(i / 10, fd)

  • Call putc_fdr(i % 10 + '0', fd)

  • Sum the return value of both and do nothing with it.

Notice that it can call the functions in either order.

In case i = 0 it will:

  • return 0

Which won't do anything really and is just a number in the middle of your code. You need to call a function to write 0, not just say "0"

0

Since binary + is unsequenced, you need to enforce the desired ordering of evaluating the operands. Most of the time, printing individual digits means you want to print the MSD first, so you defer printing digits until you have established the MSD. This means you want to recurse first, and print while returning from the recursive calls.

If you want to keep your current code structure, you can use the comma operator, ,, to sequence the two calls. To fix your dilemma, we detect when the input is a single digit.

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
    ssize_t ret = 0;
    return (i / 10 != 0
            ? ret = putuint_fdr(i / 10, fd),
              ret + putc_fdr(i % 10 + '0', fd)
            : putc_fdr(i + '0', fd));
}

This assumes write does not return an error in the middle of printing your number. If you want to add additional robustness, you should try to account for that situation as well.


In a comment to this answer, you asked:

There is no way to don't use a variable and to keep sequenced calls? (the ret ssize_t)

You need some sort of variable to add the result of two sequenced function calls. However, you can hide the assignment by passing the result of the first function call in as a parameter to the second function call.

ssize_t     putc_fdr(char c, int fd, ssize_t ret)
{
    return ret + write(fd, &c, sizeof(char));
}

ssize_t     putuint_fdr(uintmax_t i, int fd)
{
    return putc_fdr(i%10 + '0', fd,
                    i/10 ? putuint_fdr(i/10, fd) : 0);
}
jxh
  • 69,070
  • 8
  • 110
  • 193