void* argument to get the result of a function

F

foice

Hello to everybody. I read, and succesfully implented, some example of
use of a void* argument to pass a generic type argument to a function.
As far as I understand the trick is to recast the pointer to a pointer
of the correct type and then use this pointer as usual.

int f(void * input) {
float * x =(float*) input;
flaot value;
value=*x
cout<<value<<endl;

return 0
}

Now suppose that I want to compute something can I store this
"something" into a void* that is an argument of the function? I tried
this, but the value of the variable is not changed, as when I make a
cout it gives the same value of the initialization :( .

int f(void * argument) {

float result;
result=0;

argument=&result;

return 0
}

int main() {
float p;
p=11;
f( &p);
cout<<p<<endl;
return 0;
}

Any idea about what I am mistaking?
thanks a lot
Roberto
 
J

Jonathan Lee

Hello to everybody. I read, and succesfully implented, some example of
use of a void* argument to pass a generic type argument to a function.
As far as I understand the trick is to recast the pointer to a pointer
of the correct type and then use this pointer as usual.

int f(void * input) {
float * x =(float*) input;
flaot value;
value=*x
cout<<value<<endl;

return 0

}

.... er... so you _know_ that input should be a float pointer, but
you're accepting a void* and then converting, instead of simply
requiring the correct pointer? ... I hope this is for practice
or something...
Now suppose that I want to compute something can I store this
"something" into a void* that is an argument of the function? I tried
this, but the value of the variable is not changed, as when I make a
cout it gives the same value of the initialization :( .

int f(void * argument) {

float result;
result=0;

argument=&result;

return 0

}

You're assigning to "argument" rather than "the thing argument
is pointing to". This is a common mistake when learning about
pointers.

Basically, on entry to the function, argument points to p.
And you'd like p to be changed. But what you're actually
doing is saying "now let argument point to result".

The correct notation would usually be

*argument = result; // the star is a dereference

but since you have a void* instead of the (correct)
float* you need a cast:

float* argument_f = (float*)argument;
*argument_f = result;

Again, I hope this is for an exercise, because circumventing
the type checking mechanism C++ has is generally a bad
idea.

--Jonathan
 
B

Bo Persson

foice said:
Hello to everybody. I read, and succesfully implented, some example
of use of a void* argument to pass a generic type argument to a
function. As far as I understand the trick is to recast the pointer
to a pointer of the correct type and then use this pointer as usual.

int f(void * input) {
float * x =(float*) input;
flaot value;
value=*x
cout<<value<<endl;

return 0
}

Now suppose that I want to compute something can I store this
"something" into a void* that is an argument of the function? I
tried this, but the value of the variable is not changed, as when I
make a cout it gives the same value of the initialization :( .

int f(void * argument) {

float result;
result=0;

argument=&result;

return 0
}

int main() {
float p;
p=11;
f( &p);
cout<<p<<endl;
return 0;
}

Any idea about what I am mistaking?
thanks a lot
Roberto

Using a void* argument is often a mistake itself. :)

However, just like you cast the 'input' to a float*, you have to cast
the 'argument':

*((float*)argument) = result;


But if you know that the parameter really is a float*, why complicate
it this way?


Bo Persson
 
J

Jonathan Lee

but since you have a void* instead of the (correct)
float* you need a cast:

   float* argument_f = (float*)argument;
   *argument_f = result;

Actually, I may as well also mention to drop the whole C-style
cast and use one of the C++ casts:

float* argument_f = static_cast<float*>(argument);
*argument_f = result

or in one line

*(static_cast<float*>(argument)) = result;

--Jonathan
 
F

foice

However, just like you cast the 'input' to a float*, you have to cast
the 'argument':

*((float*)argument) = result;

Thank you very much for the reply. This turns out to make my thing
work. I was confusing the address and the value ...

About the void* ... Until 3 hours ago I did not even know that one can
actually use a *void :) and according to your comments I was on the
way to the heaven of the good coder ... Unfortunately I encountered on
my way this library to make numerical integration that uses this void*
to allow you to pass whatever type of variable to the function that
you want to integrate.

That's why I cannot avoid using this "dirty" void* ... it is just the
argument of a function in a library ...

Thanks again
Roberto
 
V

Vladimir Jovic

foice said:
About the void* ... Until 3 hours ago I did not even know that one can

No, can not dereference void*
actually use a *void :) and according to your comments I was on the
way to the heaven of the good coder ... Unfortunately I encountered on

or a bad coder ;)
my way this library to make numerical integration that uses this void*
to allow you to pass whatever type of variable to the function that
you want to integrate.

Feel free to throw that book to garbage. Any c++ book that suggests you
to use void* is bad.
 
R

Ruslan Mullakhmetov

Actually, I may as well also mention to drop the whole C-style
cast and use one of the C++ casts:

float* argument_f = static_cast<float*>(argument);
*argument_f = result

or in one line

*(static_cast<float*>(argument)) = result;

--Jonathan

if i'm not mistaken it's better to use reinterpret_cast which meaning is
as it easy to guess reinterpreting the value without any modification
and runtime overhead.

I got question too: does (float*) argument and
static_cast<float*>(argument) produced the same (NONE) code ?
 
J

Jonathan Lee

if i'm not mistaken it's better to use reinterpret_cast which meaning is
as it easy to guess reinterpreting the value without any modification
and runtime overhead.

I'm sure both are no-ops in most cases. But static_cast guarantees
this particular cast is correct (assuming argument was a float*
originally). This guarantee, plus the likelihood of no performance
difference, makes me prefer static_cast.
I got question too: does (float*) argument and
static_cast<float*>(argument) produced the same (NONE) code ?

I'm sure they produce the _same_ code, though I'd have to check
the documentation on cast notation (i.e., "C-style cast") to
be sure that the two are equivalent. But, given that they are
both casts to pointers of an intrinsic type.. it seems likely.

Furthermore, this is probably "no code". I can't see, for
example, void* and float* having different representations on
x86 machines. I've heard that some CPUs have different
pointers for floats than chars, which might mean void* has
a different representation (since it is required to represent
both). In such a case, code would be generated.

--Jonathan
 
J

Jonathan Lee

Um, I don't have the original message in front of me, but wasn't
argument passed as void*? static_cast makes no guarantee whatsoever
that casting void* to some other pointer type is correct. void* has no
type information. static_cast does type checking when used on a pointer
to an object type to convert to a related object type.

Hence my qualification: "assuming argument was a float* originally".

(Not looking at the original message, but I think that was a
reasonable assumption.)

[expr.static.cast] guarantees that cvT* -> void* -> cvT* is correct.
It even gives the example

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true

--Jonathan
 
J

Jonathan Lee

I guess I'm reacting to "guarantees this particular cast is correct".
If argument was a float* in the first place, a C-style cast and a
static_cast do exactly the same thing. And if argument was not a float*
they also do the same thing. So I don't see what the "guarantee" here
is.

Ah, I see. When I mentioned the guarantee originally, it was in the
context of static_cast vs reinterpret_cast, i.e., that static_cast
says this conversion to void* and back is fine, whereas I don't
believe reinterpret_cast does.

The general point I was trying to make was to favour the other
casts over reinterpret_cast, if there was any choice. The bit about
C-style casts hadn't crept into the discussion at that time.

--Jonathan
 
A

Alf P. Steinbach /Usenet

* Pete Becker, on 29.07.2010 21:35:
Okay, so I muddled things with my automatic reaction that when someone
talks about guarantees they're contrasting with a C-style cast. You're
absolutely right, of course: the result of a round-trip conversion
through a reinterpert_cast<void*> is unspecified.

A reinterpret_cast roundtrip conversion through void* is not unspecified, but is
guaranteed to yield the original pointer, by §5.2.10/7 (and §3.9.2/4).


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach /Usenet

* Pete Becker, on 30.07.2010 01:22:
5.2.10/7 (second sentence):

Except that converting an rvalue of type “pointer to T1†to the type
“pointer to T2â€
(where T1 and T2 are object types and where the alignment requirements
of T2
are no stricter than those of T1) and back to its original type yields
the original
pointer value, the result of such a pointer conversion is unspecified.

void is not an object type, so void* does not meet the requirements in
parentheses.

Right, I didn't see that.

But there is already a known defect that sentence, namely direct contradiction
between its "Except that ..., the result ... is unspecified", and §9.2/17, "A
pointer to a POD-struct object, suitably converted using reinterpret_cast,
points to its initial member (or if that member is a bit-field, then to the unit
in which it resides) and vice versa", which is at least one more case where the
result /is/ specified.

And that sentence would, with literal interpretation, force round-trip
conversion guarantee for all object pointer types (of suitable alignment) as
intermediary, but not for void*, where the compiler would be free to sort of
mess up things by always producing the nullpointer value, say.

As I see it that can't have been the intention, since it is absurd and of no
practical value.

And the existing defect in the same sentence means that it does suffer from
known lack of rigorousness, hence more likely that the absurdity is a defect,
and not the result of moronic intention, yes? :)

The result is unspecified.

Yeah, now you point it out I agree that it's formally unspecified -- *but*,
that's IMO a defect. Anyway, it's absurd. The standard isn't about providing
means and ways of the compiler messing up things in malicious ways.

Note that 3.9.2/4 does not say that void* is a pointer to object type;
rather, it says that void* can be used to point to an object of unknown
type.

Yes, I understood that.


Cheers & hth., & thanks,

- Alf
 
R

Ruslan Mullakhmetov

Furthermore, this is probably "no code". I can't see, for
example, void* and float* having different representations on
x86 machines. I've heard that some CPUs have different
pointers for floats than chars, which might mean void* has
a different representation (since it is required to represent
both). In such a case, code would be generated.
>
thanks, i've known that C++ guarantee that all pointers to any objects
are of the same size but didn't take into account that it can be the
largest possible pointer on target platform.

by the way, yesterday i turned over the pages of Satters' book
(exceptional C++) and found his note that С++ type casting operators
were chosen to be long enough with the purpose to make their use more
complicated (and force programmers to doubt their use necessity).
 
J

James Kanze

* Pete Becker, on 30.07.2010 01:22:

[...]
Right, I didn't see that.
But there is already a known defect that sentence, namely
direct contradiction between its "Except that ..., the result
... is unspecified", and §9.2/17, "A pointer to a POD-struct
object, suitably converted using reinterpret_cast, points to
its initial member (or if that member is a bit-field, then to
the unit in which it resides) and vice versa", which is at
least one more case where the result /is/ specified.
And that sentence would, with literal interpretation, force
round-trip conversion guarantee for all object pointer types
(of suitable alignment) as intermediary,

I don't see where you read that. The first element of
a POD-struct object must have have the same address as the
complete object, which means that it must be suitably aligned
for the complete object. Consider the case of a word addressed
machine, where char* contains extra information specifying the
byte in the word. The address of a POD-struct type (or int, or
anything but a char type) doesn't contain this information.
Converting a char* to some other pointer type, then back, looses
this information, so the resulting char* would point to the
first char in the word, and not the char it originally pointed
to. If the first element in the POD-struct is a char, however,
it is the first char in the first word of the POD-struct, so the
results still satisfy the requirements.
but not for void*,
where the compiler would be free to sort of mess up things by
always producing the nullpointer value, say.

Except that void* is guaranteed to have the same size and
representation as char*, so any guarantees for char* sort of
apply to void* as well. (I think. The guarantee concerning the
same size and representation were present in C; I presume that
C++ makes the same guarantee.)
 
A

Alf P. Steinbach /Usenet

* James Kanze, on 30.07.2010 12:18:
* Pete Becker, on 30.07.2010 01:22:
[...]
A reinterpret_cast roundtrip conversion through void* is not
unspecified, but is guaranteed to yield the original pointer, by
§5.2.10/7 (and §3.9.2/4).
5.2.10/7 (second sentence):
Except that converting an rvalue of type “pointer to T1” to
the type “pointer to T2” (where T1 and T2 are object types
and where the alignment requirements of T2 are no stricter
than those of T1) and back to its original type yields the
original pointer value, the result of such a pointer
conversion is unspecified.
void is not an object type, so void* does not meet the requirements in
parentheses.
Right, I didn't see that.
But there is already a known defect that sentence, namely
direct contradiction between its "Except that ..., the result
... is unspecified", and §9.2/17, "A pointer to a POD-struct
object, suitably converted using reinterpret_cast, points to
its initial member (or if that member is a bit-field, then to
the unit in which it resides) and vice versa", which is at
least one more case where the result /is/ specified.
And that sentence would, with literal interpretation, force
round-trip conversion guarantee for all object pointer types
(of suitable alignment) as intermediary,

I don't see where you read that.

5.2.10/7 (second sentence), it's what it specifies.

The first element of
a POD-struct object must have have the same address as the
complete object, which means that it must be suitably aligned
for the complete object. Consider the case of a word addressed
machine, where char* contains extra information specifying the
byte in the word. The address of a POD-struct type (or int, or
anything but a char type) doesn't contain this information.
Converting a char* to some other pointer type, then back, looses
this information, so the resulting char* would point to the
first char in the word, and not the char it originally pointed
to.

Yeah, that's what my "of suitable alignment" is about.

It seems that you violently agree with me. :)

If the first element in the POD-struct is a char, however,
it is the first char in the first word of the POD-struct, so the
results still satisfy the requirements.

Regarding this statement, I was a bit hasty: the compiler is only free to mess
up things if the original object is not a POD struct or first member of such. It
seems a very peculiar license to mess up, very arbitrary; but I think is just
defect.

Except that void* is guaranteed to have the same size and
representation as char*, so any guarantees for char* sort of
apply to void* as well. (I think. The guarantee concerning the
same size and representation were present in C; I presume that
C++ makes the same guarantee.)

Yeah. As mentioned, this seems to be an additional defect in /the same
sentence/, that is, 5.2.10/7 (second sentence).


Cheers,

- Alf
 

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
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top