sprintf problem

W

William Payne

Hello, I want to display the address a pointer points to in hexadecimal form
in the same way my debugger displays it.
Say I have P* ptr; where P is some type.

I tried:
std::sprintf(message, "%#0x, (unsigned int)ptr);

But that gives me: 0xFFFF for example, when I want 0x0000FFFF, i.e., I dont
want to drop any leading zeros. I know this is just a small cosmetic
problem, but I still would like to know how to accomplish this.

Thanks for any replies!

/ WP
 
M

Mike Wahler

William Payne said:
Hello, I want to display the address a pointer points to in hexadecimal form
in the same way my debugger displays it.
Say I have P* ptr; where P is some type.

I tried:
std::sprintf(message, "%#0x, (unsigned int)ptr);

But that gives me: 0xFFFF for example, when I want 0x0000FFFF, i.e., I dont
want to drop any leading zeros. I know this is just a small cosmetic
problem, but I still would like to know how to accomplish this.

Thanks for any replies!

#include <stdio.h>

#define char_count (sizeof (unsigned int) * 2)

int main()
{
unsigned int i = 0;
int *ptr = &i;
char message[2 * sizeof *ptr] = {0};

sprintf(message, "%0*x", 2 * sizeof ptr, (unsigned int)ptr);

puts(message);
return 0;
}

Notes:

The result of casting a pointer to unsigned int is implementation defined.

The format specifier indicating a pointer is %p.

The format of the text produced with the %p specifier is implementation
defined.

The size of type 'unsigned int' is not necessarily four bytes (but must be
at least two bytes).

The size of a byte is not necessarily eight bits (but must be at
least eight bits).

IOW: the above code is not portable.

-Mike
 
M

Mike Wahler

Mike Wahler said:
#include <stdio.h>

#define char_count (sizeof (unsigned int) * 2)

This macro is not used. Just a 'mental note'
I forgot to throw away. :)

-Mike
 
M

Mike Wahler

Mike Wahler said:

Using C++ IOStreams:

#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>

int main()
{
int i = 0;
int *ptr = &i;
std::eek:stringstream oss;

oss << std::hex
<< std::setfill('0')
<< std::setw(2* sizeof *ptr)
<< ptr
<< '\n';

std::cout << oss.str().c_str() << '\n';
return 0;
}


-Mike
 
W

William Payne

Mike Wahler said:
Using C++ IOStreams:

#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>

int main()
{
int i = 0;
int *ptr = &i;
std::eek:stringstream oss;

oss << std::hex
<< std::setfill('0')
<< std::setw(2* sizeof *ptr)
<< ptr
<< '\n';

std::cout << oss.str().c_str() << '\n';
return 0;
}


-Mike

Thanks Mike! This last example is totally portable? I need portability
across MSVC 7.1 and GCC 3.4.2, but I prefer using completely standard
methods that does not rely on undefined behaviour.

/ WP
 
M

Mike Wahler

William Payne said:
Thanks Mike! This last example is totally portable?

No. The same issues exits about conversion from integer
to pointer types, and about type size assumptions.
I need portability
across MSVC 7.1 and GCC 3.4.2,

The above isn't *universally* portable, but should be portable
among most PC operating systems.
but I prefer using completely standard
methods

There's no standard way to convert an integer to a pointer.
You can further generalize by factoring 'CHAR_BIT' into the
calculation of the output field width. But you need only
be concerned about this if you intend to port to systems
where 'CHAR_BIT' != 8.
that does not rely on undefined behaviour.

Note that undefined behavior and implementation defined behavior
are distinct specifications. The above code has implementation
defined behavior, not undefined.

-Mike
 
J

Jack Klein

Notes:

The result of casting a pointer to unsigned int is implementation defined.

If and only if unsigned int is large enough to hold the pointer. See
paragraph 4 of 5.2.10 reinterpret_cast.
The format specifier indicating a pointer is %p.

The format of the text produced with the %p specifier is implementation
defined.

The size of type 'unsigned int' is not necessarily four bytes (but must be
at least two bytes).

No, it must not.
The size of a byte is not necessarily eight bits (but must be at
least eight bits).

Taking your last two statements above, you should be able to see why I
objected to the first one. I'm working on a 16-bit DSP right now
where CHAR_BIT is 16 and sizeof(unsigned int) is 1. It has a
reasonably conforming free-standing C++ implementation.

I have also used a 32-bit DSP where all of the integer types, char
through long, all had 32 bits and sizeof == 1. C only though, it
didn't have a C++ compiler.
IOW: the above code is not portable.

-Mike

The code isn't even necessarily defined. On 16-bit platforms with 32
bit pointers (MS-DOS, TI2812, Philips XA, for example), the behavior
is undefined. Likewise on a lot of the newer 64-bit Windows/*nix
implementations, where ints have 32 bits and pointers have 64.
 
M

Mike Wahler

Jack Klein said:
defined.

If and only if unsigned int is large enough to hold the pointer. See
paragraph 4 of 5.2.10 reinterpret_cast.


No, it must not.

Right. Should have said "at least sixteen bits."
Taking your last two statements above, you should be able to see why I
objected to the first one.

Yes. :)
I'm working on a 16-bit DSP right now
where CHAR_BIT is 16 and sizeof(unsigned int) is 1. It has a
reasonably conforming free-standing C++ implementation.

I have also used a 32-bit DSP where all of the integer types, char
through long, all had 32 bits and sizeof == 1. C only though, it
didn't have a C++ compiler.


The code isn't even necessarily defined. On 16-bit platforms with 32
bit pointers (MS-DOS, TI2812, Philips XA, for example), the behavior
is undefined.

Which specific expressions are the trouble (i.e. undefined
rather than imp-defined)?

-Mike
 
J

Jack Klein

Right. Should have said "at least sixteen bits."


Yes. :)


Which specific expressions are the trouble (i.e. undefined
rather than imp-defined)?

The C++ standard says (5.2.10 Reinterpret cast, p4)

"A pointer can be explicitly converted to any integral type large
enough to hold it. The mapping function is implementation defined
[Note: it is intended to be unsurprising to those who know the
addressing structure of the underlying machine. ]"

This is the old undefined behavior because one or more cases are
specifically defined and the case under discussion is not one of them.
It is undefined by lack of definition. The fact that a pointer may be
explicitly converted by reinterpret_cast (or C cast) to any integer
type enough to hold it implicitly states that it may not be converted
to an integer type that is not wide enough to hold it.

In this case, I like the wording of the C standard better, it is more
explicit (C99 6.3.2.3 Pointers p6):

"Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type."

C99 provides for (optional) typedefs for intptr_t and uintptr_t, which
an implementation may define in <stdint.h> (almost certain to become
<cstdint> some day) if such types exist that can hold any pointer
type.

So on a CHAR_BIT 8 implementation:

double d = 50000.0;
double *dp = & d;
unsigned char uc;

uc = d; /* range exceeded, undefined behavior */
uc = dp; /* since pointers must be wider than 8 bits, ub */
 
V

Vinod Patel

William Payne said:
Hello, I want to display the address a pointer points to in hexadecimal form
in the same way my debugger displays it.
Say I have P* ptr; where P is some type.

I tried:
std::sprintf(message, "%#0x, (unsigned int)ptr);

But that gives me: 0xFFFF for example, when I want 0x0000FFFF, i.e., I dont
want to drop any leading zeros. I know this is just a small cosmetic
problem, but I still would like to know how to accomplish this.

Thanks for any replies!

/ WP

Assuming there are 8 octets for an address:-
std::sprintf(message, "0x%08x", (unsigned int)ptr);
should serve your purpose.

Vinod
 
M

ma740988

Jack Klein said:
On Mon, 13 Sep 2004 23:44:36 GMT, "Mike Wahler" [...]


I have also used a 32-bit DSP where all of the integer types, char
through long, all had 32 bits and sizeof == 1. C only though, it
didn't have a C++ compiler.
IOW: the above code is not portable.

-Mike

The code isn't even necessarily defined. On 16-bit platforms with 32
bit pointers (MS-DOS, TI2812, Philips XA, for example), the behavior
is undefined. Likewise on a lot of the newer 64-bit Windows/*nix
implementations, where ints have 32 bits and pointers have 64.

It's interesting working with the 2812 and trying to maintain
portability with - for our purposes - a power pc.

ifdef 2812
// 16 bit character
else
//
etc
 

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,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top