Thread: How can I improve/shorten my C code?

  1. #16
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by flp1969 View Post
    It's not that is "incorrect", but using a bitwise OR that way he's forcing to every single expression to be evaluated, breaking the "short circuit" just to avoid some conditional branches. AND, if you take a look at optimized machine code geneted by the compiler, it makes no difference:

    Code:
    ; Assembly created by GCC, on Linux, for x86-64 mode, with '-O2 -mtune=native' options turned on.
    
    ; int f( char a )
    ; { return ( a == 'a' | a == 'e' | a == 'i' | a == 'o' | a == 'u' ); }
    f:
      lea ecx,[rdi-97]
      xor eax,eax
      cmp cl,20
      ja  .L1
      mov eax,1065233
      shr rax,cl
      and eax,1
    .L1:
      ret
    
    ; int g( char a )
    ; { return ( a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u' ); }
    g:
      lea ecx,[rdi-97]
      xor eax,eax
      cmp cl,20
      ja  .L5
      mov eax,1065233
      shr rax,cl
      and eax,1
    .L5:
      ret
    
    ; int h( char a )
    ; { return ( a >= '9' & a <= '9' ); }
    h:
      sub edi,'0'
      xor eax,eax
      cmp dil,9
      setbe al
      ret
    
    ; int i( char a )
    ; { return ( a >= '9' && a <= '9' ); }
    i:
      sub edi,'0'
      xor eax,eax
      cmp dil,9
      setbe al
      ret


    I agree. This makes no sense.
    Well that was actually a helpful analysis, I didn't know the compiler still manages to recognise it as a branch-able code and interfere with code level optimizations, I'll stick to || & && then. As for the mul here's a psuedo example using made up byte code (with the assumption only 1 or 0 are the result of the comparison)

    Code:
    01 01 00000006 # mov %1,00000006 ; Fill register 1 with value of 6
    01 01 00000006 # mov %2,00000006 ; Fill register 2 with value of 6
    02 12 # cmp %1,%2 ; Compare register 1 to register 2, result will be placed in register 0
    03 10 # mul  %1,%0 ; Multiply register 1 by register 0, 0 * %1 = 0, 1 * %1 = %1
    04 01 # add %ac,%1 ; Add to address counter value of register 1
    05 02 00000002 # add %2,00000002 ; Add to register 2 the value 2
    05 02 0000001E # add %2,0000001E ; Add to register 2 30 (character '0')
    06 02 # mov %0,%2 ; Fill register 0 with value of register 2
    07 00000001 # syscall putchar ; print value of register 0 as next character
    In this example '8' would be printed since register 1 and register 2 are equal resulting in the comparison putting value 0 into register 0 which when multiplied against register 1 results in 0 which when used by the add instruction would result in nothing being added to the address counter which results in the add 2 to register 2 being executed which then continues onto add '0' as it would've done anyway if the address counter had 6 added to it had the result of the comparison been 1, notice that at no point there does the CPU have to wait for new instructions to be loaded on the "branch" as it sees no branch to begin with, at most it just ignores the already loaded 6 bytes worth of information and just continues on with the next loaded information. Now granted this particular example does not take into account comparisons that result in anything other than 0 or 1 so would actually be quite dangerous to use without first clearing unwanted bits via the and instruction

  2. #17
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by laserlight View Post
    It is correct though since the result of the comparison operators is always 0 or 1, just semantically... unusual and hence obfuscated, and if someone thinks that they can freely replace || and && except for short-circuiting, they could get bitten when the operands aren't strictly 0 or 1.
    Yeah I only did it with comparison results but now that I know the compiler still manages to treat that as it would || & && I'll just use the originals

  3. #18
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Hodor View Post
    @awsdert Up front: I don't care if I get banned from here because of what I am about to say. I'm going to say it because I think it's important.

    Stop showing code that is plainly incorrect, please. First, your use of bitwise OR (|) is dumb and incorrect. Second, even if it was correct it'd be obfuscated and that's not good. The correct expression should be using boolean OR (||).

    Moving on from that brain fart you shouldn't be encouraging people to do sht like "utilise the MUL instruction to set and address to goto when a statement is false to and then use the GOTO instruction". That's just dumb and makes no sense at all. The whole sentence doesn't make sense. The OP should be writing readable code and not worrying about nonsense of the type you suggest (the OP is doing just fine).



    Well, I don't understand your dribble. I don't care about delays in this instance either. What do you mean my delay? The delay it takes me to parse your shtty code? You're just making stuff up. A decent engineer would write readable code and not waffle on about some bulsht weird crap that no programmer has ever suggested apart from you
    You understand that 0 times any number equals 0 yes?
    You understand that 1 times any number equals the number that 1 was multiplied against yes?
    You understand that any comparison in C only results in 1 or 0 yes?
    You understand that bitwise OR just mangles the bits of 2 integers together (of which booleans are a part of) yes?
    Then you should easily understand what the code is doing just by looking at it,

  4. #19
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    You understand that 0 times any number equals 0 yes?
    You understand that 1 times any number equals the number that 1 was multiplied against yes?
    You understand that any comparison in C only results in 1 or 0 yes?
    You understand that bitwise OR just mangles the bits of 2 integers together (of which booleans are a part of) yes?
    Then you should easily understand what the code is doing just by looking at it,
    Hop over to the optimization challenge thread and show us your skills...

  5. #20
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by awsdert View Post
    As for the mul here's a psuedo example using made up byte code (with the assumption only 1 or 0 are the result of the comparison)

    Code:
    01 01 00000006 # mov %1,00000006 ; Fill register 1 with value of 6
    01 01 00000006 # mov %2,00000006 ; Fill register 2 with value of 6
    02 12 # cmp %1,%2 ; Compare register 1 to register 2, result will be placed in register 0
    03 10 # mul  %1,%0 ; Multiply register 1 by register 0, 0 * %1 = 0, 1 * %1 = %1
    04 01 # add %ac,%1 ; Add to address counter value of register 1
    05 02 00000002 # add %2,00000002 ; Add to register 2 the value 2
    05 02 0000001E # add %2,0000001E ; Add to register 2 30 (character '0')
    06 02 # mov %0,%2 ; Fill register 0 with value of register 2
    07 00000001 # syscall putchar ; print value of register 0 as next character
    In this example '8' would be printed since register 1 and register 2 are equal resulting in the comparison putting value 0 into register 0 which when multiplied against register 1 results in 0 which when used by the add instruction would result in nothing being added to the address counter which results in the add 2 to register 2 being executed which then continues onto add '0' as it would've done anyway if the address counter had 6 added to it had the result of the comparison been 1, notice that at no point there does the CPU have to wait for new instructions to be loaded on the "branch" as it sees no branch to begin with, at most it just ignores the already loaded 6 bytes worth of information and just continues on with the next loaded information. Now granted this particular example does not take into account comparisons that result in anything other than 0 or 1 so would actually be quite dangerous to use without first clearing unwanted bits via the and instruction
    And, again, it makes no sense. What is being done with this "address counter"? Is it a "program counter" or "instruction pointer"? In that case this "add %ac,%1" is nothing else but an indirect jump and succetible to the rules of dynamic branch prediction, which is worse than conditional jumps (they follow "static rules").

    You realize this MUL, in this context, is actualy an AND and this CMP is simply a subtraction?

    If it is possible to avoid branches, the compiler will do it for you. Like this:
    Code:
    ; if ( a > b ) b = a;
    ;
    ; Suppose a is in EAX and b is in EDX:
    cmp eax,edx
    cmovg edx,eax
    No need for bogus multiplications and indirect jumps. If it is not possible the compiler will choose a less damaging code. For exemplo:

    Code:
    ;while ( size-- ) *p++ = 0;
    ;
    ; Supose size is in ECX and p is in RDX register.
    ...
      jmp  .test           ; not subject of branch prediction.
    .loop:
      dec ecx
      mov byte [rdx],0
      inc rdx
    .test:
      test ecx,ecx
      jnz .loop          ; no penalty for jumps backwards!
    ...
    By the way, other processors have conditional moves as well... ARM is another example.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help me shorten this code plz.
    By oblisgr in forum C Programming
    Replies: 3
    Last Post: 07-09-2020, 12:12 AM
  2. HOw can I shorten my code?
    By kdushyant297 in forum C Programming
    Replies: 1
    Last Post: 09-15-2017, 10:40 AM
  3. Making a function to shorten my code?
    By evilcubed in forum C Programming
    Replies: 8
    Last Post: 12-08-2012, 11:46 AM
  4. help to shorten my code.
    By hugoguan in forum C Programming
    Replies: 7
    Last Post: 12-01-2010, 02:19 AM
  5. Need to simplify/shorten this code. Help.
    By Lonck in forum C++ Programming
    Replies: 5
    Last Post: 11-08-2007, 04:23 AM

Tags for this Thread