0

I have an array which I wish to assign zeros to all positions in a given range (positions 10 to 24, in this case). I'm doing this:

ulong st[25];
...
for(int i = 10; i < 25; ++i) st[i] = 0x00UL;

Is this the fastest way to do that? It seems that there should be a faster way without a loop, given that it's a contiguous position in memory, but I don't know what that would be (perhaps XORing that memory space with itself? If so, how would I do that?)

Any ideas?

Edy Bourne
  • 5,679
  • 13
  • 53
  • 101
  • 8
    `memset()` I wouldn't worry too much. Sounds like premature optimisation to me. Come back to it if you find things are too slow – John3136 Dec 07 '17 at 22:53
  • 1
    An alternative is [`memset()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/memset.html); it can be implemented as an assembly language built-in that works faster. – Jonathan Leffler Dec 07 '17 at 22:53
  • You could also hard code the 25 element array ( `ulong st[25] = { 0x00L, 0x00L, 0x00L ... };` – erik258 Dec 07 '17 at 23:02
  • 1
    @DanFarrell The loop starts at 10 .. but if he meant to initialize the whole array to 0, `ulong st[25] = { 0x00UL };` should do it with much less typing! https://stackoverflow.com/questions/201101/how-to-initialize-all-members-of-an-array-to-the-same-value – yano Dec 07 '17 at 23:05
  • ah, that's nice. And much less effort if the number changes too. – erik258 Dec 07 '17 at 23:07
  • 3
    If your compiler doesn't optimize that down to whatever is the fastest way to zero out a range of memory on your processor, then your compiler isn't very good. GCC will do it just fine. – Lee Daniel Crocker Dec 07 '17 at 23:23
  • `memset(st + 10, 0, sizeof st[0] * (25 - 10 + 1));` or let the compiler optimize. – chux - Reinstate Monica Dec 07 '17 at 23:29

3 Answers3

2

I'd be tempted to write it with the simple loop as you have done, and leave the optimisation trickery to the compiler.

If you are in any doubt that the compiler has done a good job then check the generated assembly.

As a rule of thumb, programmers are more expensive than computers. So keep maintenance cheap; i.e. write clear code whenever possible.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
1

You could use memset()for that: http://man7.org/linux/man-pages/man3/memset.3.html

Might be the same thing under the covers though.

erik258
  • 14,701
  • 2
  • 25
  • 31
1

memset can do the job. See the illustrative example where 14 elements are zeroed.

#include <stdio.h>
#include <string.h> // for memset

void print_array(unsigned long *array, int len)
{
    int i;
    for (i = 0; i<len; i++ )
    {
         printf("%lu ", array[i]);
    };

    printf("\n");   
}

int main()
{
     unsigned long st[25];

    // initialize all elements in the table (25 of them)
    for(int i = 0; i < 25; ++i) 
        st[i] = i;

    // Assign zeroes from position 10 to position 24 (14 zeroes)
    // Note: The last position of the st[] table is not zeroed on purpose!

    // remember of the type of the array `sizeof(unsigned long)`:
    memset( st+10, 0, 14*sizeof(unsigned long) );

    print_array(st, 25);

    return 0;
}

OUTPUT:

0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 24 

Assembly for both cases x86-64 gcc 7.2 (no optimization!):

int main()
{
    unsigned long st[25];
    memset( st+10, 0, 15*sizeof(unsigned long) );
    return 0;
}

  main:
  push rbp
  mov rbp, rsp
  sub rsp, 208
  lea rax, [rbp-208]
  add rax, 80
  mov edx, 120
  mov esi, 0
  mov rdi, rax
  call memset
  mov eax, 0
  leave
  ret


int main()
{
    unsigned long st[25];
    for(int i = 10; i < 25; ++i) st[i] = 0;
    return 0;
}  
  main:
  push rbp
  mov rbp, rsp
  sub rsp, 88
  mov DWORD PTR [rbp-4], 10
.L3:
  cmp DWORD PTR [rbp-4], 24
  jg .L2
  mov eax, DWORD PTR [rbp-4]
  cdqe
  mov QWORD PTR [rbp-208+rax*8], 0
  add DWORD PTR [rbp-4], 1
  jmp .L3
.L2:
  mov eax, 0
  leave
  ret
sg7
  • 6,108
  • 2
  • 32
  • 40