declaring functions moving input pointer

I

Ilya N. Golubev

There is already one function processing pointer values this way. And
there may easily appear more, including wrappers for this function.

For purposes of further discussion, consider simplified function,
`consume'. It has one arg, INBUF, that points to a variable that
points to the first character in the input buffer. The function never
modifies characters pointed to by `*INBUF'. It, however, updates
the `*INBUF' value to point to the byte following the last byte
successfully consumed.

We can declare this function

void consume (const char **);

or

void consume (char **);

Which one is appropriate, wrt semantics of `const' as designed in
current C language standards? In any case, applications may have both
`char *' and `const char *' variables, which must be passed and
updated as described above. In any case, the conversions are be
needed to do such a passing, like this.

void consume (const char **);
/* ... */
char *buf;
consume ((const char **) &buf);

Or

void consume (char **);
/* ... */
const char *buf;
consume ((char **) &buf);

Currently, if T is type, any `T*' value may be assigned to `const T*'
one. This is not the case for assigning `T**' values to `const T**'
ones. Why would allowing this be incorrect / dangerous?

Or should we completely avoid declaring functions with `**' args like
these, and specify them like `write' instead? That is, to take `const
char *' arg and return or otherwise pass to caller a `ssize_t' value
saying how much should be added to said `const char *' value before
passing it to the next call.


The function needs to update `size_t' value in addition to `char *'
one anyway, and this should be also the case for its wrappers. So one
might declare `consume' like this.

typedef struct {
const char *p;
size_t s;
} ciov_t;
void consume (ciov_t *IR);

So that is updates both `IR->p' and `IR->s'.

Never seen such a declarations, however. `writev', in particular,
does not use input structures with `const void *' for data to write.
This will even cause trouble for application writers needing to pass
such a data pointers to `writev'. What would be dangerous / incorrect
in declaring functions this way?
 
M

Michael Mair

Ilya said:
There is already one function processing pointer values this way. And
there may easily appear more, including wrappers for this function.

For purposes of further discussion, consider simplified function,
`consume'. It has one arg, INBUF, that points to a variable that
points to the first character in the input buffer. The function never
modifies characters pointed to by `*INBUF'. It, however, updates
the `*INBUF' value to point to the byte following the last byte
successfully consumed.

We can declare this function

void consume (const char **);

or

void consume (char **);

Which one is appropriate, wrt semantics of `const' as designed in
current C language standards? In any case, applications may have both
`char *' and `const char *' variables, which must be passed and
updated as described above. In any case, the conversions are be
needed to do such a passing, like this.

void consume (const char **);
/* ... */
char *buf;
consume ((const char **) &buf);

Or

void consume (char **);
/* ... */
const char *buf;
consume ((char **) &buf);

Currently, if T is type, any `T*' value may be assigned to `const T*'
one. This is not the case for assigning `T**' values to `const T**'
ones. Why would allowing this be incorrect / dangerous?

Have a look at the comp.lang.c FAQ, especially
http://c-faq.com/ansi/constmismatch.html

BTW: I'd rather use the "secure" form of "const char **" and have
no cast, i.e.
char *buf;
const char *cbuf;
....
cbuf = buf;
consume(&cbuf);
Avoiding the cast can help you find errors like
consume(cbuf);
which is not possible for
consume((const char **)buf);
Or should we completely avoid declaring functions with `**' args like
these, and specify them like `write' instead? That is, to take `const
char *' arg and return or otherwise pass to caller a `ssize_t' value
saying how much should be added to said `const char *' value before
passing it to the next call.

Note that in the context of standard C, there is no "ssize_t" but
there is in POSIX. From the following, I guess that you really mean
size_t.
The function needs to update `size_t' value in addition to `char *'
one anyway, and this should be also the case for its wrappers. So one
might declare `consume' like this.

typedef struct {
const char *p;
size_t s;
} ciov_t;
void consume (ciov_t *IR);

So that is updates both `IR->p' and `IR->s'.

Never seen such a declarations, however. `writev', in particular,
does not use input structures with `const void *' for data to write.
This will even cause trouble for application writers needing to pass
such a data pointers to `writev'. What would be dangerous / incorrect
in declaring functions this way?

I am not sure whether I understood you correctly.
Do you want to modify data pointed to by a pointer to const type?
This is most of the time a bad idea; if you can guarantee that
you had a pointer to unqualified type to start with, then
"removing the const" may work. If the data was const qualified
from the start, it may well reside in some sort of non-writable
memory.
Or do you want to read data pointed to by IR->p?

The "updates" throws me off, to be honest.

Cheers
Michael
 

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,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top