[Swan-dev] const version of str_*()

Andrew Cagney andrew.cagney at gmail.com
Sat Sep 14 14:55:40 UTC 2019


Lets assume:

  id_t id1, id2 = ...
  dn_t dn = ... // I don't think that exists

In the beginning we had the convention:

  char b1[DN_LEN], b2[ID_LEN], b3[ID_LEN];
  idtoa(&id1, b1, sizeof(b1));
  idtoa(&id2, b2, ID_LEN);
  dntoa(&dn, b3, DN_LEN);
  printf("id1=%s dn=%s\ id2=%sn", b1, b2, b1);

But then we found that, over time, errors were creeping in, for instance:

- the wrong size was used when declaring the string buffer
- the wrong buffer and/or len was passed to *toa()
- the parameters on the print line didn't line up with the string

So things evolved:
- buf's type became strong
- the conversion routine returned a pointer to buf
and the code would now be written as:

  id_t id1, id2 = ...
  dn_t dn = ... // I don't think that exists

  id_buf bid;
  dn_buf bdn;
  printf("id1=%s dn=%s\ id2=%sn", str_id(&id1,&bid), str_dn(&dn,
&bdn), str_id(id2, &bid))

which is a definite improvement.

But here's a different problem.  We've code micro-optimized as follows:

  char buf[ID_LEN]
  idtoa(&id1, buf);

  if (dbg) printf("id1 = %s\n", buf);
  ...
  if (dbg) printf("id 2 = %s\n", buf);

presumably to minimise the number of string conversions.  Except, with
certain irony, when !dbg and things matter, it will make an
unnecessary call.
I'm changing the code to:

  if (dbg) {
    id_buf b;
    printf("id1 = %s\n", str_id(&id1, &b));
  |
  ...
  if (dbg) {
    id_buf b;
    printf("id2 = %s", str_id(&id2, &b));
  }

so its more readable (the calls are on the debug path anyway).

However, I wonder if we we can tweak this further and eliminate the
need to declare the buffers; and the desire to optimise, vis:

   id_buf id_str(const id_t *id) __attribute__((const))
   ...
   printf("id1 = %s\n", id_str(&id1).buf);
   printf("id2 = %s\n", id_str(&id2).buf);
   printf("id1 = %s\n", id_str(&id1).buf);

https://lwn.net/Articles/285332/

- the need to declare the buffer is gone
- the compiler can eliminate duplicate calls
- the odds of passing wrong buffers is reduced further

it should also be efficient.  Small structures are returned in 1-2
registers; and larger structures are returned by reference, the above
is compiled as:

   id_buf tmp;
   str_id(&tmp, &id)
   tmp.buf

making it equivalent to the old str_id() call.

have fun,
Andrew


More information about the Swan-dev mailing list