This is the mail archive of the
mailing list for the glibc project.
Variations of memset()
- From: Matthew Wilcox <willy at infradead dot org>
- To: libc-alpha at sourceware dot org
- Date: Fri, 4 Aug 2017 10:11:18 -0700
- Subject: Variations of memset()
- Authentication-results: sourceware.org; auth=none
I would like to propose adding some useful variations of memset()
to libc, and potentially to ISO C. My apologies if these have been
proposed before; I have not been able to find any evidence of them being
Add the following 8 functions to libc, the first three as independent
functions and the others as convenience aliases for them:
void *memset16(uint16_t *s, uint16_t v, size_t count);
void *memset32(uint32_t *s, uint32_t v, size_t count);
void *memset64(uint64_t *s, uint64_t v, size_t count);
void *memset_s(unsigned short *p, unsigned short v, size_t count);
void *memset_i(unsigned int *p, unsigned int v, size_t count);
void *memset_l(unsigned long *p, unsigned long v, size_t count);
void *memset_ll(unsigned long long *p, unsigned long long v, size_t count);
void *memset_p(void **p, void *v, size_t count);
Each of these routines is functionally equivalent to:
for (i = 0; i < count; i++)
p[i] = v;
1. The above for-loop is a relatively common idiom in existing programs
today. Experiments show approximately a doubling in performance after
replacing the naive implementation above with hand-optimised assembler
for ARM, x86 and PowerPC. Other architectures are likely to see similar
2. Searching the web for 'memset16' or 'memset32' shows a number of people
asking for implementations, constructing implementations (sometimes
badly) and using implementations across a wide variety of programs.
Having these functions as part of the standard library would give people
a single place to focus their efforts.
3. Making this part of the standard library would give compiler writers
a common idiom to transform the above for-loop into, improving code which
wasn't converted to use one of the memset variations.
4. C++ has a std::fill function to allow assignment to a range. This
would be the equivalent functionality in C for base types.
A more generic:
memfill(void *buf, size_t bufsize, const void *pat, size_t patsize)
has previously been proposed by Lars Wirzenius and would provide more
functionality than the independent routines above. My research indicates
that this is awkward to use; frequently the value to be assigned is
constructed in-place, and assigning it to a temporary variable in order
to take the address and pass it to memfill() is clumsy.
Replacing the 'count' of elements with the number of bytes leads to
confusion and unnecessary questions on the implementation side about what
to do if 'n' is not a multiple of 'sizeof v'. Likewise, specifying a
'void *' destination instead of a properly typed destination leads to
confusion around endianness and correct behaviour of pointers which are
not aligned to 'sizeof v'.
I have considered making the return type of these functions 'void'
as the return value is rarely useful. But I thought it better to keep
compatibility with memset(). I also considered making them return the
same type that they were called with, but I don't think that's useful
Adding memset8() or memset_c() as aliases of memset() would not be
terribly useful in my opinion. At this time, I am not proposing adding
memset_f(), memset_d() or memset_ld(), though I can certainly see the
utility in floating-point heavy programs. Variants for some other types
(size_t, ptrdiff_t, wchar_t, the _Complex or _Bool types) could also