I'm not very happy with the do {} while() statement in C

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: I'm not very happy with the do {} while() statement in C

Post by Ras »

syzygy wrote:But he was probably not thinking very much about BASIC (which is from 1964 and was probably hardly used for serious programming).
At least, it was used enough to draw Dijsktra's expressed disapproval. But yeah, Fortran wasn't that much better back then, and the spaghetti gotos were global. I think that C's goto only shares the name with the ancient goto. Probably, setjmp/longjmp is the real C equivalent, and even that has its proper use.

The only thing I'd wish for is computed goto to be officially included in the C standard, i.e. the goto via jumptables.

I can't judge whether the Linux code is of questionable quality, but even in case it should be, it certainly isn't because goto is used for local error handling.
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: I'm not very happy with the do {} while() statement in C

Post by Ras »

syzygy wrote:
mar wrote:I certainly don't consider break/continue harmful - this must be simply another myth.
But not an existing myth.
There was a version of the MISRA coding standard (for embedded) that actually flagged out break and continue.
mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: I'm not very happy with the do {} while() statement in C

Post by mar »

Ras wrote:There was a version of the MISRA coding standard (for embedded) that actually flagged out break and continue.
Not very clever (trying to avoid "outright dumb"), assuming written by non-programmers or people who have no clue about how compilers work and what they actually do.
syzygy
Posts: 5557
Joined: Tue Feb 28, 2012 11:56 pm

Re: I'm not very happy with the do {} while() statement in C

Post by syzygy »

Ras wrote:
syzygy wrote:
mar wrote:I certainly don't consider break/continue harmful - this must be simply another myth.
But not an existing myth.
There was a version of the MISRA coding standard (for embedded) that actually flagged out break and continue.
I see... duh :?

So the myth does in fact exist and it seems the reason for banning break/continue from the MISRA coding standard is precisely that they are hidden forms of goto.

Of course the same rationale can be used to ban for and while from the MISRA coding standard, after which you're stuck with just using recursion. Until someone realises that a jsr is just a hidden form of jmp.

But it seems MISRA-C:2004 did allow one break statement per loop! 8-)
User avatar
lucasart
Posts: 3232
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: I'm not very happy with the do {} while() statement in C

Post by lucasart »

Michael Sherwin wrote:
mar wrote:
Michael Sherwin wrote:In the do while loop I have to execute instructions that at some point will not need to be executed. It is not really a problem in this simple initiation example. But still it seems like a poor design. It would be perfect if the do while worked like this.

Code: Select all

         k = i + dir[j];
        if (initBoard[k])  {
          y = k / 10; x = k - y * 10 - 1; y -= 2;
          ts = y * 8 + x;
          dirKi&#91;sq&#93; |= &#40;u64&#41;1 << ts;
          do &#123;
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;;
            k += dir&#91;j&#93;;
          &#125; while &#40;initBoard&#91;k&#93;) &#123;
            y = k / 10; x = k - y * 10 - 1; y -= 2;
            ts = y * 8 + x;
          &#125;
        &#125;
 
If it would execute the code in the braces before looping back to the do statement. Maybe there is away around this minor dilemma. I just do not know what it is?
What "poor design" are you talking about? If you want early exit, just use break inside infinite loop. What you propose is beyond ugly.

Code: Select all

         for&#40;;;)
         &#123; 
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;; 
            k += dir&#91;j&#93;; 

            if (!initBoard&#91;k&#93;)
              break;

            y = k / 10; x = k - y * 10 - 1; y -= 2; 
            ts = y * 8 + x; 
          &#125; 
Beauty is in the eye of the beholder. Break while an efficient solution is nothing more than a goto. And any goto is considered poor design by some. It is considered unfortunate by some that we must resort to using goto in some situations. The ugliness that you are referring to I think is that it looks like a regular while loop. I thought of that so I am now thinking do {} while () first {}

But it is just an idea.
"Beauty is in the eye of the beholder". This is such a BS argument used to justify just about anything. No, beauty in code is 99% of the time objective, and your code does not belong to the 1% exception. Your code smells, and Martin just showed you how to write it properly. Don't blame C's while syntax for your smelly code. Blame yourself.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: I'm not very happy with the do {} while() statement in C

Post by Michael Sherwin »

lucasart wrote:
Michael Sherwin wrote:
mar wrote:
Michael Sherwin wrote:In the do while loop I have to execute instructions that at some point will not need to be executed. It is not really a problem in this simple initiation example. But still it seems like a poor design. It would be perfect if the do while worked like this.

Code: Select all

         k = i + dir&#91;j&#93;;
        if &#40;initBoard&#91;k&#93;)  &#123;
          y = k / 10; x = k - y * 10 - 1; y -= 2;
          ts = y * 8 + x;
          dirKi&#91;sq&#93; |= &#40;u64&#41;1 << ts;
          do &#123;
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;;
            k += dir&#91;j&#93;;
          &#125; while &#40;initBoard&#91;k&#93;) &#123;
            y = k / 10; x = k - y * 10 - 1; y -= 2;
            ts = y * 8 + x;
          &#125;
        &#125;
 
If it would execute the code in the braces before looping back to the do statement. Maybe there is away around this minor dilemma. I just do not know what it is?
What "poor design" are you talking about? If you want early exit, just use break inside infinite loop. What you propose is beyond ugly.

Code: Select all

         for&#40;;;)
         &#123; 
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;; 
            k += dir&#91;j&#93;; 

            if (!initBoard&#91;k&#93;)
              break;

            y = k / 10; x = k - y * 10 - 1; y -= 2; 
            ts = y * 8 + x; 
          &#125; 
Beauty is in the eye of the beholder. Break while an efficient solution is nothing more than a goto. And any goto is considered poor design by some. It is considered unfortunate by some that we must resort to using goto in some situations. The ugliness that you are referring to I think is that it looks like a regular while loop. I thought of that so I am now thinking do {} while () first {}

But it is just an idea.
"Beauty is in the eye of the beholder". This is such a BS argument used to justify just about anything. No, beauty in code is 99% of the time objective, and your code does not belong to the 1% exception. Your code smells, and Martin just showed you how to write it properly. Don't blame C's while syntax for your smelly code. Blame yourself.
You silly billy, you are making way to much out of it by a factor of about 100, lol.
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
Ras
Posts: 2487
Joined: Tue Aug 30, 2016 8:19 pm
Full name: Rasmus Althoff

Re: I'm not very happy with the do {} while() statement in C

Post by Ras »

syzygy wrote:after which you're stuck with just using recursion.
That's not allowed either, and that's actually one of the saner points of MISRA, given the stack sizes in embedded systems and the risk of stack overflow.

"Not allowed" doesn't mean "must not be used"; it means when it is used, you have to have a process in place with review, technical analysis and signatures to prove that (a) it is necessary, and (b) doesn't do harm. If it is the best solution, it can be done, but it can't be done out of negligence or lazyness.
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: I'm not very happy with the do {} while() statement in C

Post by Sven »

Michael Sherwin wrote:This is what I have so far
Hi Mike, this is a bit closer to how Jumbo would write it in C ;-)

He found another way to write your do-while loop, and he thought that your clever SQUARE64/SQUARE120 macros are correct but a bit too clever to understand immediately, so he wrote some very simple macros instead. I hope he did not make any errors ...

Code: Select all

#include <assert.h>

enum &#123; QUIT = 0, THINK, GETCMD &#125;;

#define s32 int
#define u64 unsigned long long

#define CLEVER_SQUARE64&#40;x&#41; ((((&#40;x&#41; / 10&#41; - 2&#41; << 3&#41; + (&#40;x&#41; - (&#40;x&#41; / 10 * 10&#41; - 1&#41;)
#define CLEVER_SQUARE120&#40;x&#41; ((((&#40;x&#41; >> 3&#41; + 2&#41; * 10&#41; + ((&#40;x&#41; & 7&#41; + 1&#41;)

#define FILE64&#40;s64&#41;         (&#40;s64&#41; & 7&#41;
#define RANK64&#40;s64&#41;         (&#40;s64&#41; >> 3&#41;
#define FILE120&#40;s120&#41;       ((&#40;s120&#41; - 21&#41; % 10&#41;
#define RANK120&#40;s120&#41;       ((&#40;s120&#41; - 21&#41; / 10&#41;
#define SQUARE64_FR&#40;f,r&#41;    ((&#40;r&#41; << 3&#41; + &#40;f&#41;)
#define SQUARE120_FR&#40;f,r&#41;   (&#40;10 * &#40;r&#41;) + &#40;f&#41; + 21&#41;
#define SQUARE64&#40;s120&#41;      SQUARE64_FR&#40;FILE120&#40;s120&#41;, RANK120&#40;s120&#41;)
#define SQUARE120&#40;s64&#41;      SQUARE120_FR&#40;FILE64&#40;s64&#41;, RANK64&#40;s64&#41;)

#define BIT64&#40;x&#41;            (&#40;u64&#41; 1 << &#40;x&#41;)

void validateMacros&#40;)
&#123;
#ifndef NDEBUG
  s32 r, f;
  for &#40;r = 0; r < 8; r++) &#123;
    for &#40;f = 0; f < 8; f++) &#123;
      s32 s64  = SQUARE64_FR&#40;f, r&#41;;
      s32 s120 = SQUARE120_FR&#40;f, r&#41;;

      assert&#40;s64 >= 0&#41;;
      assert&#40;s64 < 64&#41;;

      assert&#40;s120 >= 21&#41;;
      assert&#40;s120 <  99&#41;;

      assert&#40;FILE64&#40;s64&#41; == f&#41;;
      assert&#40;RANK64&#40;s64&#41; == r&#41;;

      assert&#40;FILE120&#40;s120&#41; == f&#41;;
      assert&#40;RANK120&#40;s120&#41; == r&#41;;

      assert&#40;SQUARE64&#40;s120&#41; == s64&#41;;
      assert&#40;SQUARE120&#40;s64&#41; == s120&#41;;

      assert&#40;SQUARE64&#40;s120&#41; == CLEVER_SQUARE64&#40;s120&#41;);
      assert&#40;SQUARE120&#40;s64&#41; == CLEVER_SQUARE120&#40;s64&#41;);
    &#125;
  &#125;
#endif
&#125;

void Think&#40;void&#41;;
void Initialize&#40;void&#41;;
void GetCmd&#40;void&#41;;

u64 dirKn&#91;64&#93;;
u64 dirKi&#91;64&#93;;

u64 dir7p&#91;64&#93;;
u64 dir9p&#91;64&#93;;
u64 dir7m&#91;64&#93;;
u64 dir9m&#91;64&#93;;
u64 dir1p&#91;64&#93;;
u64 dir8p&#91;64&#93;;
u64 dir1m&#91;64&#93;;
u64 dir8m&#91;64&#93;;

u64 *const dirPtr&#91;8&#93; = &#123; dir7p, dir9p, dir7m, dir9m, dir1p, dir8p, dir1m, dir8m &#125;;

s32 mode = GETCMD;

void Think&#40;) &#123;

&#125;

void GetCmd&#40;) &#123;
  mode = QUIT;
&#125;

void Initialize&#40;) &#123;
  validateMacros&#40;);

  s32 const dir&#91;8&#93; = &#123; 9, 11, -9, -11, 1, 10, -1, -10 &#125;;
  s32 const din&#91;8&#93; = &#123; 8, 12, 19, 21, -8, -12, -19, -21 &#125;;
  s32 const isOffBoard&#91;120&#93; = &#123;
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  &#125;;

  s32 fs64;
  for &#40;fs64 = 63; fs64 >= 0; fs64--) &#123;
    s32 fs120 = SQUARE120&#40;fs64&#41;;
    s32 i;
    dirKn&#91;fs64&#93; = 0;
    dirKi&#91;fs64&#93; = 0;
    for &#40;i = 7; i >= 0; i--) &#123;
      s32 ts120 = fs120 + din&#91;i&#93;;
      if (!isOffBoard&#91;ts120&#93;) &#123;
        dirKn&#91;fs64&#93; |= BIT64&#40;SQUARE64&#40;ts120&#41;);
      &#125;
      dirPtr&#91;i&#93;&#91;fs64&#93; = 0;
      ts120 = fs120 + dir&#91;i&#93;;
      if (!isOffBoard&#91;ts120&#93;) &#123;
        dirKi&#91;fs64&#93; |= BIT64&#40;SQUARE64&#40;ts120&#41;);
        do &#123;
          dirPtr&#91;i&#93;&#91;fs64&#93; |= BIT64&#40;SQUARE64&#40;ts120&#41;);
          ts120 += dir&#91;i&#93;;
        &#125; while (!isOffBoard&#91;ts120&#93;);
      &#125;
    &#125;
  &#125;
&#125;

s32 main&#40;)
&#123;
  Initialize&#40;);

  while &#40;mode&#41; &#123;
    if &#40;mode == THINK&#41; Think&#40;);
    GetCmd&#40;);
  &#125;
  return 0;
&#125;
Michael Sherwin
Posts: 3196
Joined: Fri May 26, 2006 3:00 am
Location: WY, USA
Full name: Michael Sherwin

Re: I'm not very happy with the do {} while() statement in C

Post by Michael Sherwin »

Hi Sven, I made a post then deleted it because I had a hallucination that I made a mistake. Now my mind is all Jumboed up, I mean Jumbled up. Thanks for Jumbo's input! This thread has been educational. The reason that I am spending so much time here is because I want to start right and stay consistent throughout the coding process. A big eared thanks! :D
If you are on a sidewalk and the covid goes beep beep
Just step aside or you might have a bit of heat
Covid covid runs through the town all day
Can the people ever change their ways
Sherwin the covid's after you
Sherwin if it catches you you're through
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: I'm not very happy with the do {} while() statement in C

Post by bob »

Michael Sherwin wrote:
mar wrote:
Michael Sherwin wrote:In the do while loop I have to execute instructions that at some point will not need to be executed. It is not really a problem in this simple initiation example. But still it seems like a poor design. It would be perfect if the do while worked like this.

Code: Select all

         k = i + dir&#91;j&#93;;
        if &#40;initBoard&#91;k&#93;)  &#123;
          y = k / 10; x = k - y * 10 - 1; y -= 2;
          ts = y * 8 + x;
          dirKi&#91;sq&#93; |= &#40;u64&#41;1 << ts;
          do &#123;
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;;
            k += dir&#91;j&#93;;
          &#125; while &#40;initBoard&#91;k&#93;) &#123;
            y = k / 10; x = k - y * 10 - 1; y -= 2;
            ts = y * 8 + x;
          &#125;
        &#125;
 
If it would execute the code in the braces before looping back to the do statement. Maybe there is away around this minor dilemma. I just do not know what it is?
What "poor design" are you talking about? If you want early exit, just use break inside infinite loop. What you propose is beyond ugly.

Code: Select all

         for&#40;;;)
         &#123; 
            dirPtr&#91;j&#93;&#91;sq&#93; |= (&#40;u64&#41;1 << ts&#41;; 
            k += dir&#91;j&#93;; 

            if (!initBoard&#91;k&#93;)
              break;

            y = k / 10; x = k - y * 10 - 1; y -= 2; 
            ts = y * 8 + x; 
          &#125; 
Beauty is in the eye of the beholder. Break while an efficient solution is nothing more than a goto. And any goto is considered poor design by some. It is considered unfortunate by some that we must resort to using goto in some situations. The ugliness that you are referring to I think is that it looks like a regular while loop. I thought of that so I am now thinking do {} while () first {}

But it is just an idea.
A break is not "just a goto". It is a goto that can only go to ONE place in the code. The end of the loop. Far different from a regular goto that can jump anywhere within the current code. THAT is what makes the goto so hated, it makes code hard to read when you have to look everywhere for the target label. Not so with the break...