473,387 Members | 1,891 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Restricted pointer parameters in printf()

It's my understanding that the printf() function is declared as

int printf(const char * restrict format, ...);

in stdio.h. And loosely speaking, if a parameter is declared as
restricted, then accesses to the object must go through that parameter.

Does this mean that

printf("%s", "%s");

is illegal if the string literals are coalesced into the same pointer?
printf() would be accessing the same object through different
parameters, one of which is declared as restricted.

Another possibility is

printf("%s is tricky", "is tricky");

since the string literal objects can again overlap even though their
pointers have different values. Is that code potentially illegal?

Thanks for your thoughts,
-Peter

--
Pull out a splinter to reply.
Nov 14 '05 #1
5 2552
On Sat, 10 Apr 2004 04:46:37 GMT, Peter Ammon
<ge******@splintermac.com> wrote in comp.lang.c:
It's my understanding that the printf() function is declared as

int printf(const char * restrict format, ...);

in stdio.h. And loosely speaking, if a parameter is declared as
restricted, then accesses to the object must go through that parameter.

Does this mean that

printf("%s", "%s");

is illegal if the string literals are coalesced into the same pointer?
printf() would be accessing the same object through different
parameters, one of which is declared as restricted.

Another possibility is

printf("%s is tricky", "is tricky");

since the string literal objects can again overlap even though their
pointers have different values. Is that code potentially illegal?

Thanks for your thoughts,
-Peter


With the exception of the destination strings for (v)s(n)printf(),
members of the *printf() family never modify memory passed in via a
pointer to char.

The restrict keyword is completely unnecessary and has no effect on
objects that are not modified. It's purpose is to allow the compiler
to perform optimizations based on the fact that modifying one object
is guaranteed not to change the value of some other object. There is
no possibility of that happening when the objects are not modified.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #2
Jack Klein wrote:
On Sat, 10 Apr 2004 04:46:37 GMT, Peter Ammon
<ge******@splintermac.com> wrote in comp.lang.c:

It's my understanding that the printf() function is declared as

int printf(const char * restrict format, ...);

in stdio.h. And loosely speaking, if a parameter is declared as
restricted, then accesses to the object must go through that parameter.

Does this mean that

printf("%s", "%s");

is illegal if the string literals are coalesced into the same pointer?
printf() would be accessing the same object through different
parameters, one of which is declared as restricted.

Another possibility is

printf("%s is tricky", "is tricky");

since the string literal objects can again overlap even though their
pointers have different values. Is that code potentially illegal?

Thanks for your thoughts,
-Peter

With the exception of the destination strings for (v)s(n)printf(),
members of the *printf() family never modify memory passed in via a
pointer to char.

The restrict keyword is completely unnecessary and has no effect on
objects that are not modified.


Why's that?
It's purpose is to allow the compiler
to perform optimizations based on the fact that modifying one object
is guaranteed not to change the value of some other object. There is
no possibility of that happening when the objects are not modified.


Correct me if I'm wrong, but I thought that the restrict keyword was
defined in terms of "accesses," which would includes reads as well as
writes?

--
Pull out a splinter to reply.
Nov 14 '05 #3
On Sat, 10 Apr 2004 06:50:48 GMT, Peter Ammon
<ge******@splintermac.com> wrote in comp.lang.c:
Jack Klein wrote:
> On Sat, 10 Apr 2004 04:46:37 GMT, Peter Ammon
> <ge******@splintermac.com> wrote in comp.lang.c:
>
>
>>It's my understanding that the printf() function is declared as
>>
>>int printf(const char * restrict format, ...);
>>
>>in stdio.h. And loosely speaking, if a parameter is declared as
>>restricted, then accesses to the object must go through that parameter.
>>
>>Does this mean that
>>
>>printf("%s", "%s");
>>
>>is illegal if the string literals are coalesced into the same pointer?
>>printf() would be accessing the same object through different
>>parameters, one of which is declared as restricted.
>>
>>Another possibility is
>>
>>printf("%s is tricky", "is tricky");
>>
>>since the string literal objects can again overlap even though their
>>pointers have different values. Is that code potentially illegal?
>>
>>Thanks for your thoughts,
>>-Peter

>
>
> With the exception of the destination strings for (v)s(n)printf(),
> members of the *printf() family never modify memory passed in via a
> pointer to char.
>
> The restrict keyword is completely unnecessary and has no effect on
> objects that are not modified.


Why's that?
> It's purpose is to allow the compiler
> to perform optimizations based on the fact that modifying one object
> is guaranteed not to change the value of some other object. There is
> no possibility of that happening when the objects are not modified.


Correct me if I'm wrong, but I thought that the restrict keyword was
defined in terms of "accesses," which would includes reads as well as
writes?


The restrict keyword has its roots in the proposed noalias keyword,
which was proposed, disagreed over vehemently, and finally not
included in the original C standard ANSI89/ISO 90.

A weakness of C compared to other languages is the possibility of
aliasing. Let's take a trivial program like this:

#include <stdio.h>

int arr1 [5] = { 2, 4, 6, 8, 10 };
int arr2 [5] = { 2, 4, 6, 8, 10 };

void some_func(int *a, int *b, int count)
{
while (count--)
{
if (*a == *b)
{
*a = *b + 2;
}
++a;
}
}

int main(void)
{
int b = 2;

some_func(arr1, &b, 5);
some_func(arr2, arr2, 5);
printf("arr1 = { %d, %d, %d, %d, %d }\n",
arr1[0],arr1[1],arr1[2],arr1[3],arr1[4]);
printf("arr2 = { %d, %d, %d, %d, %d }\n",
arr2[0],arr2[1],arr2[2],arr2[3],arr2[4]);
return 0;
}

A simple optimization in some_func() would be for the compiler to read
*b once, and cache it in a local variable or register, instead of
reading it each time. But what if b is the address of one of the ints
in the range a[0] to a[count - 1]? Let's run it and look at the
output:

arr1 = { 4, 4, 6, 8, 10 }
arr2 = { 4, 6, 6, 8, 10 }

Both calls to some_func() were made with a count of 5 and an input
array of 5 ints containing 2, 4, 6, 8, and 10. And finally, both
calls were made with a pointer to an int having the value 2.

If the compiler performed the optimization of reading *b only once and
cacheing the value, both arrays would have had identical values after
being processed by some_func(), which would have been wrong. When
some_func() is called the second time, b points to arr2[0], so the
first pass of the loop causes *b to be modified. This causes *b to
match *a on the second pass of the loop, and the code correctly
modifies both arr2[0] and arr2[1].

The price of this flexibility in C is the fact that the compiler
cannot perform the optimization of caching the value of b, since
modifying an object through pointer a could modify what b points to.

If b was defined as a pointer to a const int, the compiler could
perform that optimization. On the other hand, if b was restrict
qualified, the compiler could perform that optimization. If it did,
the results of the second function call would be wrong, but that would
be the programmer's fault, for invoking undefined behavior.

The description of the restrict keyword in the standard is rather
complex, but it still boils down to informing the compiler that the
value of an object will not be modified unexpectedly via a different
lvalue. This allows, but does not require, the compiler to perform
certain optimizations when the programmer specifies, via the restrict
keyword, that an object will not be modified through another pointer.

One of the examples from the standard might be helpful in
understanding the intent:

====
10 EXAMPLE 3 The function parameter declarations
void h(int n, int * restrict p, int * restrict q, int * restrict r)
{
int i;
for (i = 0; i < n; i++)
p[i] = q[i] + r[i];
}
illustrate how an unmodified object can be aliased through two
restricted pointers. In particular, if a and b are disjoint arrays, a
call of the form h(100, a, b, b) has defined behavior, because array b
is not modified within function h.
====

So even though the term "access" is used several times in the
definition of the restrict qualifier, it has no meaning for values
that are not modified at all within the scope of the qualifier.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #4
In article <news:N_*******************@newssvr25.news.prodigy .com>
Peter Ammon <ge******@splintermac.com> writes:
It's my understanding that the printf() function is declared as

int printf(const char * restrict format, ...);

in stdio.h. And loosely speaking, if a parameter is declared as
restricted, then accesses to the object must go through that parameter.
Yes, but this is "too loosely". :-)
Does this mean that
printf("%s", "%s");
is illegal if the string literals are coalesced into the same pointer?
... Another possibility is
printf("%s is tricky", "is tricky");


Both of these calls are OK, as I think Jack Klein noted elsethread.

If you want a simpler, yet still loose but not (I hope) *too* loose,
way to describe "restrict", think of it as you saying to the
compiler:

OK, here is this pointer "p", that has the "restrict" on it. I
promise you, Mr Compiler, that I will not change the object at
p[i] without actually *writing* p[i], so that you can make
optimization assumptions.

In other words, the compiler is allowed to assume that any change
to *(p + i) for any integer i happens by writing to *(p + j) for
some integer j such that j==i. (The draft has additional wording
that lets the programmer use expressions like ((p+2)[i-2]) as well,
for instance, but this captures the essence.)

If you never write on format[i] at all -- as is the case here,
since format[i] is const-qualified -- the compiler can assume that
format[i] never changes while printf() is doing its thing internally.

Optimization of variable accesses is mostly a matter of clever
cacheing, including "reading ahead" (so that inputs are available
by the time they are needed) and "writing behind" (so that outputs
do not cause the program to stop and wait for the output to finish).
If the only kind of cacheing you ever do is read-related, everything
"just works" -- your caches could even wind up with multiple copies
of a single variable, but they all have the same value anyway, so
who cares? :-)

Unfortunately, there are some subtler interactions when one includes
write steps. Consider the (not very good) routine:

#define OPERATE ... /* some operation here */
void operate(double *result, double *inputs, size_t n) {

*result = 0.0;
for (size_t i = 0; i < n; i++)
*result = *result OPERATE inputs[i];
}

followed by a call of the form:

double buf[N]; /* N >= 11 */
operate(buf + 10, buf, 11);

This tries to put the result in buf[10] while using buf[10] as one
of the inputs.

With no "restrict" qualifiers, this code is OK -- when i reaches 10
inside operate(), buf[10] is the accumulated result-so-far, and
it is fed back into the operation.

If you were to write "double *restrict result", the differences
between various kinds of caching begin to show up: if the input[]
array is read too soon, or the output *result pointer is not written
soon enough, input[10] will not hold the (presumably) desired value
at the right time.

Since I do not have the final C99 standard, I am not willing to
say what it might require in these cases. I *am* sure, however,
that for read-only "restrict"ed pointers (as in the printf()
example), it *is* OK to have aliases going on (despite the wording
in the draft I use, which seems to forbid it).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #5
Thanks to both Jack Klein and Chris Torek for clarifying the issues. I
also lack the official C standard and was confused by the draft. Time
to "upgrade" I suppose. :)
--
Pull out a splinter to reply.
Nov 14 '05 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Albert | last post by:
Hi, I need to pass a pointer-to-member-function as a parameter to a function which takes pointer-to-function as an argument. Is there any way to do it besides overloading the function? Here...
5
by: Peter Ammon | last post by:
It's my understanding that the printf() function is declared as int printf(const char * restrict format, ...); in stdio.h. And loosely speaking, if a parameter is declared as restricted, then...
204
by: Alexei A. Frounze | last post by:
Hi all, I have a question regarding the gcc behavior (gcc version 3.3.4). On the following test program it emits a warning: #include <stdio.h> int aInt2 = {0,1,2,4,9,16}; int aInt3 =...
17
by: Charles Sullivan | last post by:
The library function 'qsort' is declared thus: void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); If in my code I write: int cmp_fcn(...); int...
4
by: ranjmis | last post by:
Hi all, I have come across a piece of code wherein a function returns a function pointer as it seems to me but not very clear from the prototype. As shown below - although return type is void...
17
by: I.M. !Knuth | last post by:
Hi. I'm more-or-less a C newbie. I thought I had pointers under control until I started goofing around with this: ...
23
by: main() | last post by:
Hi all, I have three newbie questions : 1) According to my understanding, main function can be defined in any of the following two ways, int main(void) int main(int argc,char *argv) How...
11
by: Felix Kater | last post by:
Hi, I can compile and run this code (see below) which twice calls the function f, first with too less, second with too much arguments. But is it legal and free of memory leaks and other...
7
by: william | last post by:
My question is: Specific memory block where my pointer pointing to changed strangely, seemingly that no statement changed it. Here are two examples I got: ***********1***************** I was...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.