another very basic question :-)

S

sagi

Hello erveryone,I am a newcomer here and the word of c.
Here I have a question confused me a lot that when I read codes I
found some declaration like that:
"int regcomp(regex_t *restrict comoiled, const char *restrict
parttern, int cflags) "
or something like that
" int strnlen(const char FAR *s, int count)"
what does the "restrict" or "FAR" means?

--thanks advance
 
J

James Kuyper

sagi said:
Hello erveryone,I am a newcomer here and the word of c.
Here I have a question confused me a lot that when I read codes I
found some declaration like that:
"int regcomp(regex_t *restrict comoiled, const char *restrict
parttern, int cflags) "
or something like that
" int strnlen(const char FAR *s, int count)"
what does the "restrict" or "FAR" means?

FAR is not part of standard C. I believe that it is either a keyword or
a macro. Either way, it only works on certain systems (which don't
include any system I write programs for). You would get a better answer
than I could give you by asking in a newsgroup for the appropriate
compiler or operating system.

To understand the restrict keyword, consider the following function. It
takes as arguments a list of characters, and a string, and it adds 1 to
any character in the string which matches one of the characters in the list.

void blankchars(const char blanklist[], char string[])
{
if(blanklist == NULL || string == NULL)
return;
for( ; *blanklist; blanklist++)
{
for(size_t i=0; string; i++)
{
if(string == *blanklist)
string++;
}
}
}

What happens if this function is called as follows? :

char alphabet[] = "abcde";
blankchars(alphabet, alphabet);

On my home computer, the result of this call will be that alphabet now
contains the string "bddff". Do you understand why?

Well, that is probably not what anyone would want the function to do. In
fact, there's no reasonable thing for the function to do when the
blanklist and the string overlap in any way.

You might think that it should check for overlap between the blanklist
and the output string. The obvious way to do this would seem to be
compare blanklist, string, and strlen(blanklist) and strlen(string).
Unfortunately, if blanklist and string do NOT overlap, then comparing
them with <, >, <=, >= or by subtracting them has behavior that is not
defined by the C standard. On many machines it will work as you might
expect, but on many real machines, it will produce erroneous results or
possibly even cause your program to abort().

You can compare pointers to different arrays for equality, and there's a
perfectly portable way to check for overlap that makes use of that fact.
Just compare a pointer to every character in one string for equality
with pointers to the starting and ending characters of the other string,
and vice versa. However, it's rather inefficient.

The simplest approach is simply to document that the function is not
guaranteed to work properly if there's any overlap between the strings
pointed at by its two arguments. This is a very popular choice, and it's
the one take by the C standard library itself in most cases like that.

However, just because you've documented that restriction, doesn't mean
that that compiler knows anything about it. Because you've decided not
to worry about overlapping arguments, you could have re-written the
innermost loop as follows:

int c = *blanklist;

for(size_t i; string; i++)
{
if(string == c)
string = ' ';
}

When there is no overlap, this code produces exactly the same result as
the original program. This is a very simple optimization, and under
other circumstances, virtually any modern compiler would perform
optimizations like this one for you, even at the lowest optimization levels.

However, in this particular circumstance, the compiler cannot perform
this optimization for you. The compiler has to generate code which will
work as required by the C standard, even if string and *blanklist
refer to the same character, and that's not the case for the optimized
version of the code. With the optimized version, blankchars(alphabet,
alphabet) would produce "fffff" (on my machine). The compiler thinks
it's important to make sure that this case produces "bddff", and will
therefore not perform the optimization. It doesn't know that you don't
care about that case.

This is where "restrict" comes in. If we change the function declaration to

void blankchars(const char restrict blanklist[], char restrict string[])

then this tells the compiler that developers and users of blankchars()
will work together to make sure that string and *blanklist never
refer to the same object. That gives the compiler permission to perform
optimizations like the one above.

The down side of 'restrict' is that, if the requirements it imposes are
violated, the behavior is undefined. It's no longer the case that we can
say that the result of calling blankchars(alphabet, alphabet) is to set
alphabet to "bddff". It is now technically possible that just about
anything could happen, including causing your program to abort.

In this particular case, it is most likely to produce "fffff", but in
more complicated cases, the problems created by the permitted
optimizations could be arbitrarily bad. However, to be fair, in those
more complicated cases, the problems would probably also be pretty bad
if the "restrict" keyword was not used.
 
M

MisterE

sagi said:
Hello erveryone,I am a newcomer here and the word of c.
Here I have a question confused me a lot that when I read codes I
found some declaration like that:
"int regcomp(regex_t *restrict comoiled, const char *restrict
parttern, int cflags) "
or something like that
" int strnlen(const char FAR *s, int count)"
what does the "restrict" or "FAR" means?

FAR (and often many other ones you will see like NEAR DATA IDATA XDATA
RDATA etc. even FAR FAR are basically special compiler depedant things
which tell the compiler what sort of memory is being pointed to. This
is most common on embedded systems which can have internal RAM, external
RAM, a second external RAM chip at different addresses etc.

For example its typical for an embedded processor to have internal RAM
and external ram. So you might be able to declare variables like:

int foo[32];
int FAR foo[32];

one will take up space in internal ram and one in external ram, it all
depends on the compiler. The compiler will have documentation about
what it actually does. Typically pointers to external ram may actually
be of different size or need to page out memory etc so they also use
the FAR
 
R

REH

FAR (and often many other ones you will see like NEAR DATA IDATA XDATA
RDATA etc. even FAR FAR are basically special compiler depedant things
which tell the compiler what sort of memory is being pointed to. This
is most common on embedded systems which can have internal RAM, external
RAM, a second external RAM chip at different addresses etc.

For example its typical for an embedded processor to have internal RAM
and external ram. So you might be able to declare variables like:

int foo[32];
int FAR foo[32];

one will take up space in internal ram and one in external ram, it all
depends on the compiler. The compiler will have documentation about
what it actually does. Typically pointers to external ram may actually
be of different size or need to page out memory etc so they also use
the FAR

OT, but it is more likely he is using a compiler for a segmented
architecture, like DOS. FAR doesn't indicate any particular type of
RAM. It indicated a far pointer, which is one that contains both the
segment and offset of the address.

REH
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top