Hi Paul, > > I'm after warnings that point to undefined behaviour, and since passing a > > 'char *' in place of an 'unsigned char *', 'FILE *', or similar already > > generates a compiler warning, using 'restrict' here does not offer an > > advantage. > > It can still offer an advantage, since GCC doesn't necessarily generate a > compiler warning without the 'restrict'. For example, in the following code > GCC > complains about the call to f but not the call to g: > > void f (char *restrict, int *restrict); > void g (char *, int *); > > int > main (void) > { > int a[] = {0, 0, 0}; > void *p = a; > f (p, p); > g (p, p); > }
True. But it's pretty rare that people use 'void *' pointers and cast them to pointers of different types. Also, even a small variation of this code does not produce a warning any more: void f (char *restrict, int *restrict); void g (char *, int *); int main (void) { int a[] = {0, 0, 0}; void *p = a; f (p, a); // no warning! g (p, a); } > More generally, the role of 'restrict' for optimizations can't be easily > separated from its role for warnings. Using 'restrict' to save machine > instructions also means that it's better for GCC to generate warnings when > the > behavior would otherwise be undefined; conversely, typically when GCC > generates > warnings it's free to optimize more. Because of this close connection, when > in > doubt it's better to use 'restrict' in a way that benefits optimization as > well > as warning. It needs to be weighed against the desire not to produce warnings for valid uses. For example here: > > int snprintf (char *str, size_t size, const char *format, ...); > > ... since 'restrict' on the first parameter is going to signal a warning > > for overlaps with the 3rd, 4th, 5th, ... parameter, we don't need 'restrict' > > on the 3rd parameter. > > If we omit 'restrict' from the 3rd parameter, GCC won't warn when the 3rd > parameter overlaps with the 4th. That's a minus. Actually, GCC doesn't warn here, even with 'restrict', because the 3rd argument is a const-pointer and the 4th argument, being variadic, is treated like a const-pointer as well. Test case (enable one of the declarations): #include <stddef.h> //extern int smprintf (char *restrict, size_t, char *, ...); // no warning //extern int smprintf (char *restrict, size_t, char *restrict, ...); // warning //extern int smprintf (char *restrict, size_t, const char *, ...); // no warning //extern int smprintf (char *restrict, size_t, const char *restrict, ...); // no warning //extern int smprintf (char *restrict, size_t, const char *restrict, char *restrict); // warning //extern int smprintf (char *restrict, size_t, const char *restrict, const char *restrict); // no warning char buf[10]; int main () { char fmt[] = "%s"; smprintf (buf, sizeof buf, fmt, fmt); } > This sounds backwards. Ordinarily (without restrict) there is a contract that > prevents the compiler from optimizing the implementation in certain ways. > With > restrict, that part of the contract goes away. From the programmer's point of > view, 'restrict' places additional restrictions on the caller, not on the > callee. And appropriate use of 'restrict' signals to programmers what the > callee > can do. I agree. > This signal to humans is useful regardless of whether tools like GCC use > the signal to generate warnings or optimizations. I disagree. Given the confusion around what 'restrict' is actually about, the "signal to humans" is fuzzy. As it stands, GCC >= 8 is the best bet for a programmer to understand 'restrict'. > > The "same array" rule comes from what I understood from various explanations > > of 'restrict' on the web [1], and from what I see in the glibc headers for > > functions that have multiple output parameters of the same type: > > - splice in <bits/fcntl-linux.h>, > > - printf_arginfo_size_function in <printf.h>, > > - openpty in <pty.h>, > > - re_set_registers in <regex.h>, > > - copy_file_range in <unistd.h>. > > That stackoverflow explanation is full of confusing answers and none of them > are > particularly good. And the glibc headers evidently were not written by people > who cared about proper use of 'restrict' (possibly because they wrote the > headers before 'restrict' existed or was widely supported). ... possibly also because ISO C 99 § 6.7.3.1 is impenetrable. ... possibly also because GCC 8 was not around to teach the programmers. > > But ecvt, fcvt in <stdlib.h> have 'restrict'. You may want to register a > > glibc > > bug if you think these five functions should have 'restrict' :) > > It's not a bug. It's required by POSIX (which uses 'restrict' more carefully) > in > its older editions. See: > > https://pubs.opengroup.org/onlinepubs/009695399/functions/ecvt.html I meant the "glibc bug" the other way around: Someone could tell the glibc people that it makes sense to _add_ 'restrict' to the declarations of splice, printf_arginfo_size_function, openpty, re_set_registers, copy_file_range. Bruno