Passing a constant by reference

  • Thread starter Thread starter Bob Altman
  • Start date Start date
B

Bob Altman

Hi all,

I want to call a function that takes a void* argument and pass it the address of
a constant. Is there a way to do this without explicitly defining the constant
and then passing the address of the constant? In other words, what I *don't*
want to do is this:

const int myInt = 5;
MyFunc(&myInt);

I want to do something more like this:

MyFunct(&(int)5);

TIA - Bob
 
Bob said:
I want to call a function that takes a void* argument and pass it the address of
a constant. Is there a way to do this without explicitly defining the constant
and then passing the address of the constant? In other words, what I *don't*
want to do is this:

const int myInt = 5;
MyFunc(&myInt);

I want to do something more like this:

MyFunct(&(int)5);
A constant expression has no address; what you're asking for is meaningless.
It's like asking where the number 5 is stored in the computer. It's not
stored anywhere, it just *is*. Storage locations produce addresses, not
constant values. Aren't you accidentally confusing this with a literal
address, i.e.

MyFunc((void*) 5);

This will convert the integer 5 to a memory location and pass that as a
pointer. This will then most likely produce an access violation upon access,
since "5" is rarely a valid address, but if the "void*" is meant to merely
hold a pointer-sized value rather than an actual pointer, this might have
some meaning.
 
Bob said:
Hi all,

I want to call a function that takes a void* argument and pass it the
address of a constant. Is there a way to do this without explicitly
defining the constant and then passing the address of the constant? In
other words, what I *don't* want to do is this:

const int myInt = 5;
MyFunc(&myInt);

That won't work. Does your function actually accept a "const void *"
instead of a "void *"?
 
That won't work. Does your function actually accept a "const void *" instead
of a "void *"?

Actually, it turns out that I left the "const" off of the "void *" in my
function declaration. But I don't see how that affects my original question,
which was how to avoid explicitly declaring the constant and passing its
address.
 
Bob said:
Actually, it turns out that I left the "const" off of the "void *" in my
function declaration. But I don't see how that affects my original question,
which was how to avoid explicitly declaring the constant and passing its
address.
By taking its address. Let's get a few things straight here. This is a constant:

const int a = 5;

This is *not* a constant, but a constant expression:

5

Expressions (whether constant or not) do not *have* addresses. No storage is
allocated to them. If you want an address, you need a storage location. As I
mentioned, you can do this:

(const void*) 5

This is "the address with numerical value 5". It's not "the address of the
constant 5" because there's no such thing.

Why not take a step back and tell us what you're trying to ultimately
achieve, instead of insisting on the impossible?
 
Bob said:
Actually, it turns out that I left the "const" off of the "void *" in
my function declaration. But I don't see how that affects my
original question, which was how to avoid explicitly declaring the
constant and passing its address.

Once you add the "const" your problem should disappear:

int(5); // creates a temporary of type int
MyFunct(&(int(5))); // takes the address of this temporary, references
can be bound to temporaries only if the reference is const
 
Why not take a step back and tell us what you're trying to ultimately achieve,
instead of insisting on the impossible?

Jeroen,

Most languages support the concept of passing a constant value by reference
simply by specifying including a constant expression in the call syntax. In
"good old C", passing a pointer was as close as you could get to passing a value
"by reference", but C and C++ seem to insist that the code must explicitly
declare storage for the constant in order to obtain a pointer to it. All I'm
asking is how to get the compiler to recognize that I'm trying to pass the
address of a constant and to have the compiler allocate the constant for me.
The C/C++ compiler happily does this with string constants, but not numeric
constants. (And don't start in with "yeah but strings are really pointers".
It's still a constant expression, and the compiler allocates storage for the
constant.)
 
Ben said:
Once you add the "const" your problem should disappear:

int(5); // creates a temporary of type int
MyFunct(&(int(5))); // takes the address of this temporary, references
can be bound to temporaries only if the reference is const
This does not compile. We're talking pointers here, not references, and
there's no such thing as a void&.
 
Bob said:
Most languages support the concept of passing a constant value by reference
simply by specifying including a constant expression in the call syntax. In
"good old C", passing a pointer was as close as you could get to passing a value
"by reference", but C and C++ seem to insist that the code must explicitly
declare storage for the constant in order to obtain a pointer to it.

This is because neither C nor C++ actually *have* call-by-reference, whether
you're talking constants or not. C++ has the rather muddled concept of
passing references by value, which is almost but not quite the same thing.
All I'm asking is how to get the compiler to recognize that I'm trying to
pass the address of a constant and to have the compiler allocate the
constant for me.

That's just not in the language(s).
The C/C++ compiler happily does this with string constants, but not
numeric constants. (And don't start in with "yeah but strings are really
pointers". It's still a constant expression, and the compiler allocates
storage for the constant.)
What can I say? C and C++ are weird like that. You need to really get the
terminology straight to see where they're coming from, and strings are very
special.

"This is a string constant" is not a string constant. There's no such thing
as a "string constant" as far as the language is concerned. It's a string
literal. String literals are constant expressions which evaluate to constant
char arrays. And those arrays, in turn, decay to char pointers. This is how
you get your free "address to a constant", and it requires cooperation from
the decidedly arcane way that strings and arrays work in C and C++.

There's no such thing as a "numeric constant" in the language either. All
you have is constant expressions. Unlike arrays, which implicitly decay into
pointers, there's no way to get a pointer from a non-array expression
without assigning it to a named object, since you cannot take the address of
an expression.

C++ introduces the concept of anonymous temporaries so you can bind these to
constant references, but you cannot take their address directly. Now, typed
references are safe:

void foo(const int& a);

foo(5 + 3);

but passing an int by reference is rather pointless, as you could just pass
it by value. C++ generally eschews void* and uses templates instead to
achieve genericity:

template<typename T>
void foo(const T& t) {
...
}

foo(5 + 3);
foo(std::string("Hello, ") + std::string("world! "));

In both cases temporaries are constructed and bound to references. Now you
can even do this unsafely and get pointers by using this mechanism as an
intermediary step:

void bar(const void* v) {
// use v here but don't store it, as it'll become invalid soon!
}

template<typename T>
void foo(const T& t) {
bar(&t);
}

foo(5 + 3);
foo(std::string("Hello, ") + std::string("world! "));

The reason this works is that the temporary you pass to foo() actually has
storage when foo() calls bar(), namely as the parameter "t".

Now, be careful about that last call: what bar() actually receives is a
pointer to an std::string object, not a char*. And when we do this:

foo((std::string("Hello, ") + std::string("world! ")).c_str());

What happens *exactly* is:

- The compiler generates a temporary for the "Hello, " string.
- The compiler generates a temporary for the "world! " string.
- The compiler invokes operator+ for the temporaries, the result being
another temporary.
- The compiler invokes c_str() on that temporary, getting a const char*.
- It binds this const char* to a reference, passing that reference to foo(),
which is thus receiving a const char*&.
- foo() takes the address of this reference, yielding a const char* const*,
which is passed to bar().

And *none of this* actually involves call-by-reference! It's a wonder
programmers' heads don't explode more often.
 
That's just not in the language(s).

Thanks. That's the answer I was afraid I'd get. I'm stuck with passing
pointers 'cause I need to expose stuff using C bindings from a library that's
callable from other languages (Ada, FORTRAN, etc.).
 
Once you add the "const" your problem should disappear:
This does not compile. We're talking pointers here, not references, and
there's no such thing as a void&.

Here's one that compiles (with VC2008):

void fn1( void * p )
{
int x = *static_cast<int*>(p);
}

fn1( const_cast<int *>( &static_cast<const int &>(5) ) );

.... but I think it stinks! :)

Dave
 
David said:
Here's one that compiles (with VC2008):

void fn1( void * p )
{
int x = *static_cast<int*>(p);
}

fn1( const_cast<int *>( &static_cast<const int &>(5) ) );

... but I think it stinks! :)
Oh, right... Ben's solution actually *does* work, with a slight modification
-- a cast to a reference forces generation of a bound temporary. The trick
is that the reference has to be const. Recall that the OP actually did want
to use a const void* after all, so no further casting is necessary:

MyFunct(&static_cast<const int&>(5));

Of course, this is still unsafe. MyFunct() better not store that pointer
anywhere for later use. It does meet the original requirement of not needing
to declare a separate variable, for whatever that's worth.
 
void fn1( void * p )
Oh, right... Ben's solution actually *does* work, with a slight modification
-- a cast to a reference forces generation of a bound temporary. The trick
is that the reference has to be const. Recall that the OP actually did want
to use a const void* after all, so no further casting is necessary:

Ah, I'd forgot he'd mentioned const later on in the thread.
Of course, this is still unsafe. MyFunct() better not store that pointer
anywhere for later use.

I think that statement would apply to any local variable though.
It does meet the original requirement of not needing
to declare a separate variable, for whatever that's worth.

Yes, it's just a way of achieving the same as the more clear way of
defining a local variable - the generated code will be pretty much
identical.

Dave
 
David said:
Ah, I'd forgot he'd mentioned const later on in the thread.


I think that statement would apply to any local variable though.
True, but the scope of a temporary is even smaller than that of a local
variable, and taking the address of one is even less common (so it might not
throw up a warning flag when it really should).
 
Back
Top