passing a (const void *) into memset()

B

bob_jenkins

{
const void *p;
(void)memset((void *)p, ' ', (size_t)10);
}

Should this call to memset() be legal? Memset is of type
void *memset(void *, unsigned char, size_t)
Also, (void *) is the generic pointer type.

My real question is, is (void *) such a generic pointer type that it
can legally discard const? If this is legal, what is the point of
const, seeing how nobody's ever going to get warned about doing a
memset to a const string? And if this isn't legal, is there any
completely generic pointer type (one that can get const to be ignored)?
 
B

Ben Pfaff

{
const void *p;
(void)memset((void *)p, ' ', (size_t)10);

The casts to void and to size_t here should be dropped.
}

Should this call to memset() be legal? Memset is of type
void *memset(void *, unsigned char, size_t)
Also, (void *) is the generic pointer type.

This call to memset() is valid if and only if p points to a
modifiable object (of at least 10 bytes). That is, if it points
to the beginning of a variable declared as `char s[10];' it's
fine, but if p points into a string literal or into a variable
declared as `const char s[10];', then it's undefined.
My real question is, is (void *) such a generic pointer type that it
can legally discard const? If this is legal, what is the point of
const, seeing how nobody's ever going to get warned about doing a
memset to a const string?

The point is that the cast is necessary. If you only cast when
it's necessary, then a cast is a flashing red light saying "I'm
doing something dangerous!"

Some compilers can warn about casts that discard qualifiers.
And if this isn't legal, is there any completely generic
pointer type (one that can get const to be ignored)?

Any object pointer (in C90) can be assigned to an object of type
`const volatile void *'. (In C99 `restricted' might enter the
picture too, but I don't know much about `restricted'.) If
that's what you want, I'm not sure what you're asking for.
 
E

Eric Schmidt

{
const void *p;
(void)memset((void *)p, ' ', (size_t)10);
}

Should this call to memset() be legal?

You're passing it an uninitialized pointer. So... it's invalid,
in this case.
 
M

Mike Wahler

{
const void *p;
(void)memset((void *)p, ' ', (size_t)10);
}

Should this call to memset() be legal?

It is syntactically legal, but in your example above
it will give undefined behavior, due to the uninitialized
pointer 'p'. And if the pointer were valid, you still
get undefined behavior due to the attempt to modify
a const object.
Memset is of type
void *memset(void *, unsigned char, size_t)

Not quite.

================================================================
ISO/IEC 9899:1999 (E)

7.21.6.1 The memset function

Synopsis

1 #include <string.h>

void *memset(void *s, int c, size_t n);

Description

2 The memset function copies the value of c (converted to an
unsigned char) into each of the first n characters of the
object pointed to by s.

Returns

3 The memset function returns the value of s.
================================================================
Also, (void *) is the generic pointer type.

My real question is, is (void *) such a generic pointer type that it
can legally discard const?

Yes. But if you hadn't written the cast, many compilers would
issue a warning.

================================================================
6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any
incomplete or object type. A pointer to any incomplete or object
type may be converted to a pointer to void and back again; the
result shall compare equal to the original pointer.

2 For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type;
the values stored in the original and converted pointers shall
compare equal.
================================================================
If this is legal, what is the point of
const,

To protect from inadvertent modification. But if you choose to
consciously subvert this protection (i.e. via a cast), then the
responsibility for protection from abuse is transferred to your
shoulders. That's what casting means: it tells the compiler
"I know what I'm doing, get out of my way". If you really
don't know what you're doing, and something bad happens, then
you've performed the famous act of "shooting yourself in the foot".
seeing how nobody's ever going to get warned about doing a
memset to a const string?

But above that's not what you're doing. 'memset()'s first
parameter is *not* a const pointer. If you pass a const
pointer argument, you get what you deserve. :)
And if this isn't legal, is there any
completely generic pointer type (one that can get const to be ignored)?

'void *'

-Mike
 
L

Lawrence Kirby

It is syntactically legal, but in your example above
it will give undefined behavior, due to the uninitialized
pointer 'p'. And if the pointer were valid, you still
get undefined behavior due to the attempt to modify
a const object.

We don't know that the object is const, p can be set to point to a
non-const object. If that's possible in the program p probably shouldn't
be defined with a pointer to const type however.

....

This is a misleading statement and probably wrong. It tends to lead to
wrong conclusions about void * anyway.
Yes. But if you hadn't written the cast, many compilers would
issue a warning.

No, conversions must honour qualifier rules. Without the cast a diagnostic
is required.
================================================================
6.3.2.3 Pointers

1 A pointer to void may be converted to or from a pointer to any
incomplete or object type. A pointer to any incomplete or object
type may be converted to a pointer to void and back again; the
result shall compare equal to the original pointer.

2 For any qualifier q, a pointer to a non-q-qualified type may be
converted to a pointer to the q-qualified version of the type; the
values stored in the original and converted pointers shall compare
equal.

This tells you about the result you get from specific conversions or
sequences of conversions, there are other rules that determine WHEN such
conversions are permitted. In particular there is a constraint for
assignment in 6.5.16.1.p1

"- one operand is a pointer to an object or incomplete type and the
other is a pointer to a qualified or unqualified version of void, and
the type pointed to by the left has all the qualifiers of the type
pointed to by the right;"

Other cases of implicit conversion refer back to the assignment
specification, e.g. for function calls in 6.5.22p2:

"If the expression that denotes the called function has a type that
includes a prototype, the number of arguments shall agree with the number
of parameters. Each argument shall have a type such that its value may be
assigned to an object with the unqualified version of the type of its
corresponding parameter."
================================================================


To protect from inadvertent modification. But if you choose to
consciously subvert this protection (i.e. via a cast), then the
responsibility for protection from abuse is transferred to your
shoulders. That's what casting means: it tells the compiler "I know
what I'm doing, get out of my way". If you really don't know what
you're doing, and something bad happens, then you've performed the
famous act of "shooting yourself in the foot".


But above that's not what you're doing. 'memset()'s first parameter is
*not* a const pointer. If you pass a const pointer argument, you get
what you deserve. :)

A diagnostic. :) So you will get warned about passing pointers to const
to memset(). The original code doesn't that that though, it deliberately
casts to void * and passes a void * value to memset(). In that case a
diagnostic is not required.

There is no generic pointer type in C. Ignoring C99's restrict you can
convert any pointer type except pointers to functions to const volatile
void *. You can't convert implicitly back though where that would require
dropping qualifiers. Once you have a pointer of type const volatile void *
you still have to do something with it.

Lawrence
 
B

bob_jenkins

I think I understand now:
char *x;
const void *y;
(void)memset(x,' ',10);
(void)memset(y,' ',10);
(void)memset((void *)y,' ',10);
The first memset should be syntactically legal because a (char *) can
be passed into a (void *) argument, the second memset should not be
legal because a (const void *) cannot be passed into a (void *), and
the third memset should be syntactically legal because the explicit
cast can get around anything. If my particular lint tool tells me the
first memset is also illegal, I'll be primed to ignore complaints about
the second memset, but that would be a bug in my lint tool. Is that
correct?
 
L

Lawrence Kirby

I think I understand now:
char *x;
const void *y;
(void)memset(x,' ',10);
(void)memset(y,' ',10);
(void)memset((void *)y,' ',10);
The first memset should be syntactically legal because a (char *) can
be passed into a (void *) argument, the second memset should not be
legal because a (const void *) cannot be passed into a (void *), and
the third memset should be syntactically legal because the explicit
cast can get around anything.

True, except that there are limits on what you can cast. You can however
cast between any two pointer types, although for a lot of cases you aren't
guaranteed sensible results, or even that the program won't blow up when
executing the conversion.
If my particular lint tool tells me the
first memset is also illegal,

It may well have found a problem, but not one relating to permitted type
conversions. E.g. in the exact code above you're passing x, an
uninitialised variable, to memset(). That's the sort of problem that is
bread and butter for lint tools.
I'll be primed to ignore complaints about
the second memset, but that would be a bug in my lint tool. Is that
correct?

The second call to memset is broken, and any C compiler must generate a
diagnostic let alone picky lint tools.

Lawrence
 

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

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,969
Members
47,536
Latest member
VeldaYoung

Latest Threads

Top