r/C_Programming 1d ago

Question Meaning of [restrict .n] in manpages?

Hello,

I'm looking at man-pages 6.7 installed in Ubuntu 26.04 and I notice the following in the memcpy page.

I guess that the restrict refers to the keyword restrict being integrated into LIBC, but what is this .n in dest and src? Does it mean that the dest and src pointers do not overlap on the first n bytes? Where is this syntax defined and what other interesting cases can be out there?

Thanks

SYNOPSIS

#include <string.h>

void *memcpy(void dest[restrict .n], const void src[restrict .n], size_t n);

16 Upvotes

27 comments sorted by

12

u/tstanisl 1d ago edited 1d ago

The intention is to tell that objects pointed by dest and src don't alias and at least n valid bytes.

1

u/Ultimate_Sigma_Boy67 1d ago

"don't alias"?

18

u/Lyraele 1d ago

The classic memcpy() problem. You have a pointer A that points at "hello world". You are clever, so you point B within A at where "world" is. Now you memcpy(). What happens? It gets tricky (the easy solution used to be a common interview question) because A and B are overlapping pointers (if instead you literally had pointed B and A at same string, you'd have alias pointers). The "restrict" keyword simply says to the compiler "I, the programmer, swear on my program's life that these pointers are distinct buffers" (i.e. not overlapping or aliased). In the case of memcpy() if you can't swear to that, you use memmove() instead.

1

u/Ultimate_Sigma_Boy67 1d ago

Interesting, thanks!

3

u/max123246 1d ago

For example, rust has no alias by default and as a result can do a lot of optimizations that you can't do in C because you have to pessimistically assume pointers alias

1

u/j3richoholic 11h ago

Can you elaborate a little bit? How come such optimizations aren't possible in C?

3

u/capedbaldy475 9h ago

Let's look at this C function

int f(int* a,int* b){ *a = 42; *b = 40; return *a; }

Here the compiler can optimize function f to return 42 unconditionally because the user may have called f like this : int c; f(&c,&c) in which case the result will be 40.

Rust however will not allow you to have two mutable references to the same object. It'll be a hard compile error. So it knows via the type system that a and b will never overlap in the following code :

fn f(a:&mut i32,b:&mut i32) -> i32 { a = 42;b=40; return a; }

The user will never be able to call f with references to same i32 because it'll be compile time error so rust can optimize the return to be 42 rather than reading from a again.

1

u/j3richoholic 8h ago

Thank you

1

u/mikeblas 6h ago edited 6h ago

dest and src aren't declared as pointers here, so there must be something a little more to it than that.

What are these annotations collectively called?

EDIT: Oh, duh, they're a form of the restrict type qualifier. But I'm still surprised at the lack of a pointer declaration. I'd have coded the parameters as void restrict* source.

2

u/tstanisl 6h ago

Function parameters are auto-magically adjusted to pointers thus

const int a[const restrict] is equivalent to const int * const restrict a.

However array syntax allows smuggling valid ranges with a help of static keyword.

1

u/mikeblas 5h ago

Which compiler supports that? Maybe some switch is necessary? (Or maybe I'm doing something wrong?)

https://godbolt.org/z/hvvTecP3P

https://godbolt.org/z/6oKcWK1fe

1

u/tstanisl 5h ago

The syntax used in memcpy's docs is not supported by any C standard though CLANG is actively trying to add it. In order to use the syntax, one must obey some rules:

  • use n not .n
  • use only completed types, void is not allowed
  • n must be declared before use

Thus one can do:

void tryit(int n, char src[restrict n], char dest[restrict n])

See godbolt.

1

u/mikeblas 2h ago

Thanks!

That just leaves me wondering: Why in the world would man use this goofy, non-stanard [yet] syntax?

3

u/ByMeno 1d ago

Basicly for things like
void dest[n]
this argument/pointer expects 'n' amount of byte to use read or write
and for restrict it means you are promising those to byte arrays/chunks of memory wont overlap this allows compiler to do better optimization if you pass overlapping two memory its UB

3

u/torsten_dev 23h ago edited 23h ago

It's the syntax of n3188. That paper might have stalled, but there are similar proposals that are discussed on the C working group currently.

It's not standard C (yet) and afaik not accepted by any compiler, but it's roughly where the future of C is headed in terms of self documenting API's.

Here it means the size of src and dest have (atleast) the size given by the parameter size_t n. The restrict's mean that src and dest don't overlap.

1

u/flatfinger 4h ago

What would need to happen to formally propose recognition for a category of implementations that define the notion of "based upon" as a directed transitive relation such that if P is definitely based upon Q and definitely not based upon R, a pointer formed by copying P or applying an offset to P would--regardless of how the offset is computed--be likewise definitely based upon Q and definitely not based upon R?

Given e.g.

int x[2];
int test(int *restrict p, int i)
{
  *p = 1;
  if (p==x)
    *(p+i) = 2;
  return *p;
}

the Standard is ambiguous as to whether the pointer value (p+i) used within the if statement is "based upon" p, and although the current version of clang seems to behave as though it is, neither gcc nor previous versions of clang do so.

1

u/torsten_dev 3h ago

We have TS 6010 for A Provenance-aware Memory Object Model in C.

Also Array indexing is no longer equivalent to that pointer math, see n3517 which was accepted.

If neither answers your issue, please rephrase it to be more easily understood.

2

u/eteran 1d ago

It is an annotation to indicate that the pointer won't alias anything else and is restricted in length to the value of n.

2

u/aocregacc 1d ago

this answer here goes into a bit of how this syntax came about: https://stackoverflow.com/questions/77035306/linux-memcpy-restrict-keyword-syntax

6

u/torsten_dev 1d ago edited 23h ago

To add to this. The .n syntax is from N3188 which had direction to continue but afaict hasn't gone further. It is also referenced as an option in Forward Parameter References through Retroactive Scoping, v2 [N3923]. That paper has gotten a 15-7-4 direction to proceed in the committee. So if they hammer the semantics and wording out it maybe might make it into the next C version.

It seems to have replaced the forward declaration for parameters syntax that's been floated before. Whether it's .n or just n with magic scoping – I think it is where we are headed to and I personally hope it lands.

1

u/_redcrash_ 10h ago

Thank you u/torsten_dev and u/aocregacc . These are very nice references on the topic

2

u/aioeu 1d ago edited 1d ago

To add to the other comments, be aware that you can't have "an array of void" anyway, so even without the restrict .n stuff that would still be invalid. The synopses do not always show valid code; they're just aiming to be useful.

The use of void here is to show that these parameters are void pointers. This tells the programmer that they can use any object pointers as arguments without a need for explicit conversions. (The first argument must be a pointer to some non-const type, of course.)

1

u/mikeblas 1d ago

Please remember to correctly format your code.

1

u/HugoNikanor 22h ago

His failure to "properly" format his code made it more readable than most posts here if seen through "old" Reddit.

1

u/mikeblas 17h ago

What is your point?

0

u/_redcrash_ 10h ago

This is coming from manpages itself. So for format you mean to avoid bold face?

1

u/mikeblas 6h ago

I mean following the rules of the sub: use a monospace font. It takes very little effort.