How to transfer an address value without using pointers

H

Horacius ReX

You may well get better answers if you explain why you can't use
pointers. Is it a problem with the compiler or with your understanding
of the compiler?

the main reason is:

- this architecture consists of two units, central (A) unit and
calculation unit(B)
- in my program I need to send the information of the address of A
where the data for the calculation is stored
- pointers can not be used to transfer address information (e.g.
pointers) due to limitations on the compiler
- these two units have different memory spaces
- the way in B to retrieval info from A is by DMA tranfer using a
special function in B which needs to know the address in A in order to
transfer this data

So that's basically my problem
 
B

Bart

that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.

I did mention this in my reply:

H:>> what do you mean with intptr_t and uintptr_t ?

B:> Special int types guaranteed to be the right size for your
pointers.

I think intptr_t etc are optional in an implementation. So it is
necessary to know the right int size (long, long long etc) to use. But
this is implicit whenever int <-> pointer conversion is involved.

For typical desktop machines, I don't know how common the I32 P64
model is. If the wrong int size is used, I suspect either it will work
(because the top 32 pointer bits are zero anyway), or it will soon be
found to not work! This is a job for the compiler to warn about.

I'm guessing that in this assignment it doesn't matter.
int send(char *str);

You're passing a pointer which the assignment prohibits.
 
R

rahul

common trick? Don't you mean, common pitfall?
There are modern architectures where pointers are 64 bits and ints 32
bits, for example.
I have not come across any such machines(not to say they don't exist).
But what I asked was apart from the overflow issue, are there any
other issues? The overflow issue is solved by using (u)intptr_t
( provided the implementation provides it).
 
V

vippstar

I did mention this in my reply:

H:>> what do you mean with intptr_t and uintptr_t ?

B:> Special int types guaranteed to be the right size for your
pointers.
Only for valid pointers to void.
I think intptr_t etc are optional in an implementation. So it is
necessary to know the right int size (long, long long etc) to use. But
indeed, they are optional. It is impossible to know the 'right' size.
Regardless, it is not only about bit width.
this is implicit whenever int <-> pointer conversion is involved.
I don't understand what is implicit. There is no implicit int to/from
pointer conversion, except for initializations to constant expressions
with value 0.
For typical desktop machines, I don't know how common the I32 P64
Who cares about typical desktop machines? The standard certainly
doesn't mention or care about them in the way you describe.
model is. If the wrong int size is used, I suspect either it will work
(because the top 32 pointer bits are zero anyway), or it will soon be
found to not work! This is a job for the compiler to warn about.
Yes it will or will not work, in other words, undefined behavior.
And no, the compiler doesn't have to warn. Warning are optional and
not required by the standard, and it's not a constraint violation to
cast a pointer to (int).
I'm guessing that in this assignment it doesn't matter. It does.


You're passing a pointer which the assignment prohibits.
Indeed, in the part of my post that you snipped I say:

vipp> However, all these examples use pointers in a way or another, I
vipp> suspect your homework question was made up by someone who
doesn't
vipp> really know C.
 
V

vippstar

I have not come across any such machines(not to say they don't exist). They do
But what I asked was apart from the overflow issue, are there any
other issues? The overflow issue is solved by using (u)intptr_t
( provided the implementation provides it).
The standard doesn't mention any; in fact the standard doesn't even
mention the "oveflow issue" in that case. Just let your imagination go
wild and think of some reasons.
For example, the standard also doesn't define why fseek() could fail.
In real-world applications it could fail for pipes, sockets, etc,
which are beyond the scope of the standard; the reason the
possibilities of failure of an explicit conversion from pointer to int
is not documented is so that the standard will not restrict the
language in some way.
 
K

Keith Thompson

Horacius ReX said:
the main reason is:

- this architecture consists of two units, central (A) unit and
calculation unit(B)
- in my program I need to send the information of the address of A
where the data for the calculation is stored
- pointers can not be used to transfer address information (e.g.
pointers) due to limitations on the compiler
- these two units have different memory spaces
- the way in B to retrieval info from A is by DMA tranfer using a
special function in B which needs to know the address in A in order to
transfer this data

So that's basically my problem

What is the origin of this problem? Is this a real-world system
you're describing, or is it something created out of someone's
imagination for the sake of this exercise?

If it's a real-world system, then an address on unit A must be copied
to unit B, but on unit B it's not really an address, it's a bag of
bits that can be passed to your special DMA transfer function. In
that case, there should be some precise definition of the format in
which the address is to be transferred.

What is the declaration of this DMA transfer function? What argument
type does it expect?

And what C compiler can't pass pointers as arguments?
 
B

Bart

Only for valid pointers to void.

In that case intptr_t won't help, since we're using pointers to non-
void types.
indeed, they are optional. It is impossible to know the 'right' size.
Regardless, it is not only about bit width.
I don't understand what is implicit.

I meant in people's minds when they are reading example code with int/
pointer conversions. If you had to put everything necessary, a lot of
code would become obfuscated.
Who cares about typical desktop machines? The standard certainly
doesn't mention or care about them in the way you describe.

Sometimes you have to read between the lines in the standard. I would
also have had to write UB when deciding what should happen when a
pointer value is truncated. 99.9% of the time you just get those lower
bits, but some machine from 1957 did it another way so...
And no, the compiler doesn't have to warn.

If it's that big a deal, then maybe it should, and at standard warning
levels.

Indeed, in the part of my post that you snipped I say:

However, all these examples use pointers in a way or another
OK.

I suspect your homework question was made up by someone who
doesn't really know C.

Maybe the question was /about/ pointer and integer conversions.
 
V

viza

I have not come across any such machines(not to say they don't exist).

Almost all new desktop computers fall into this category under some of
the most common Linux distributions. I have:

tcv@rose:~ $ csizeof int
4
tcv@rose:~ $ csizeof void*
8
tcv@rose:~ $ uname -a
Linux rose 2.6.24-1-amd64 #1 SMP Sat May 10 09:28:10 UTC 2008 x86_64
GNU/Linux


My handy csizeof bash script is:
(replies on this to some other group if you please)

#! /bin/bash
# by (e-mail address removed) PUBLIC DOMAIN 2007
# usage eg:
# csizeof "struct stat" sys/types.h sys/stat.h unistd.h

cname=$(tempfile --suffix=.c)
ename=$(tempfile --suffix=.exe)

cat >"$cname" <<EOF
#include <stdio.h>
#include <stdlib.h>
EOF

for (( i= 2; i <= $#; ++i ))
do
echo "#include <${!i}>" >>"$cname"
done

cat >>"$cname" <<EOF
int main(void){
fprintf( stdout, "%zu\n", sizeof($1) );
exit( EXIT_SUCCESS );
}
EOF

gcc -o "$ename" "$cname" && chmod 700 "$ename" && "$ename"
rm -f "$cname" "$ename"
 
V

vippstar

In that case intptr_t won't help, since we're using pointers to non-
void types.
No, it's still possible to use it:
intptr_t = (intptr_t)(void *)any_ptr_type;
any_ptr_type = (void *)intptr_t_object
I meant in people's minds when they are reading example code with int/
pointer conversions. If you had to put everything necessary, a lot of
code would become obfuscated.
No it would not, if yo don't put everything necessary the code is
quite possibly errornous.
Sometimes you have to read between the lines in the standard. I would
also have had to write UB when deciding what should happen when a
pointer value is truncated. 99.9% of the time you just get those lower
bits, but some machine from 1957 did it another way so... Wrong.

If it's that big a deal, then maybe it should, and at standard warning
levels.
Actually it's up to the compiler whether to warn or not. It's not a
constraint violation and therefore does not require a diagnostic
message from the compiler, and I've already explained that in the part
that you snipped. Please don't snip parts of my post that are relevant
to the discussion.
 
V

viza

- this architecture consists of two units, central (A) unit and
calculation unit(B)
- in my program I need to send the information of the address of A where
the data for the calculation is stored - pointers can not be used to
transfer address information (e.g. pointers) due to limitations on the
compiler - these two units have different memory spaces - the way in B
to retrieval info from A is by DMA tranfer using a special function in B
which needs to know the address in A in order to transfer this data

So that's basically my problem

Can your retarded compiler pass a struct?
 
N

Nick Keighley

I not sure I believe this

the main reason is:

- this architecture consists of two units, central (A) unit and
calculation unit(B)

two processors?

- in my program I need to send the information of the address of A
where the data for the calculation is stored

- pointers can not be used to transfer address information (e.g.
pointers) due to limitations on the compiler

what limitations
- these two units have different memory spaces
ok

- the way in B to retrieval info from A is by DMA tranfer using a
special function in B which needs to know the address in A in order to
transfer this data

how does A send the address to B. Shared memory? Serial link?

would something like this help?

#include <stdio.h>

void serialize_address (void *data)
{
unsigned char *dp;
int i;

dp = (unsigned char*)(&data);


printf ("serialized address: ");
for (i = 0; i < sizeof(void*); i++)
{
printf ("%.02x ", dp);
}
printf ("\n");
}


int main(void)
{
unsigned char* data_block = "SNARK";

printf ("address: %p\n", data_block);
serialize_address (data_block);

return 0;
}


obviously code in the loop will vary depending how they communicate.

/* UNTESTED */
void send_addr_to_calc_processor (void *data)
{
unsigned char *dp;
int i;

dp = (unsigned char*)(&data);

for (i = 0; i < sizeof(void*); i++)
*(SHARED_MEM + i) = dp;

/* tell calc the address is ready */
*(SHARED_MEM + READY_FLAG) = 1;
}



--
Nick Keighley

"Almost every species in the universe has an irrational fear of the
dark.
But they're wrong- cos it's not irrational. It's Vashta Nerada."
The Doctor
 
S

santosh

Horacius said:
On Jun 17, 12:15 am, Bart <[email protected]> wrote:
yes, i tried tranferring an int with the address "coded", but
dont know how to use later in the function this address
Something like this?
#include <stdio.h>
#include <stdlib.h>
void send(int ptr){
*(int*)ptr = 1201;

int main(void) {
int A=0;



thanks! this is really what was looking for !

that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:

#include <stdio.h>

int send(char *str);

int main(void) {
char s[512];
sprintf(s, "p", malloc(1024));
send(s);
return 0;

}

int send(char *str) {
void *p;
sscanf(str, "%p", &p);
free(p);
return 0;

}

Or you can use (u)intptr_t.

However, all these examples use pointers in a way or another, I
suspect your homework question was made up by someone who doesn't
really know C.

in the question, pointers can be used wherever BUT in the arguments of
the function

Well then, make the function receive a struct object and encapsulate
your pointer in it. Or make the pointer file scope and access it
directly within your function.
 
B

Bartc

viza said:
Almost all new desktop computers fall into this category under some of
the most common Linux distributions. I have:

tcv@rose:~ $ csizeof int
4
tcv@rose:~ $ csizeof void*
8

There must be an option to select the int/pointer size surely?

Many appls would be quite happy to stay with 32-bit pointers; 64-bit ones
would just waste memory, bandwidth and performance.

For my main appl, 64-bit data (ie. 64-bit moves) would help tremendously,
but if all my data doubled in size then I'm back where I started.
 
I

Ian Collins

All popular desktop OSs (even 64 bit windows) use this model.
There must be an option to select the int/pointer size surely?
All decent compiler systems on 64 bit systems can build 64 or 32 bit
applications.
 
C

Chris Torek

the main reason is:

- this architecture consists of two units, central (A) unit and
calculation unit(B)
- in my program I need to send the information of the address of A
where the data for the calculation is stored [snippage]
- the way in B to retrieval info from A is by DMA tranfer using a
special function in B which needs to know the address in A in order to
transfer this data

Given all of this information, simply "taking the address" is
quite possibly insufficient.

Consider, for instance, the situation in which the calculation
device ("unit B" here) is on a 32-bit PCI bus, while the
system running the C program ("unit A" here) is a 64-bit-memory PC.

Suppose that the physical address of item A, on the PC, is actually
0x0000_0002_410C_59B4 (underscores inserted here for readability;
this is not a C-language constant). This address lies beyond the
four gigabyte limit of the 32-bit address range of the PCI bus, so
it is physically impossible for unit B to supply it in the first
place.

Moreover, the *virtual* address of item A within the process running
on the PC may well not be 0x0000_0002_410C_59B4. This is merely
the *physical* address that must be sent when the device on the
PCI bus wants to access the physical RAM that will hold the
representation of the value calculated by unit B. That is, when
unit B has a final answer, it must write it to physical address
0x0000_0002_410C_59B4, which the process running on unit A will
read when it reads some other virtual address (perhaps something
like 0x000719B4, for instance).

What is required, in this particular case, is to set up an "I/O
map" (or IOMMU or some similar name) that sits between the 32-bit
PCI bus and the 64-bit physical address space. (If there is no
IOMMU, some alternative strategy must be devised.) The IOMMU will
take care of mapping from a 32-bit PCI bus address to a 64-bit
address. To build the mapping, you start with the virtual address(es)
as seen by the C code running on "unit A", and translate that
(those) to the ultimate 64-bit physical address(es). Then you
obtain a sufficiently large virtual address space in the IOMMU,
and map that virtual address to the same physical page(s). You
then supply, to unit B, the "PCI side virtual address" you obtained
and mapped. When the DMA completes, you can free the virtual
address range on the IOMMU (or, depending on device access patterns,
you might allocate this range permanently, and simply remap it as
needed).

Each of these steps is quite machine-dependent. In addition, some
devices have restrictions on DMA addressing (e.g., even though a
bus might be officially "32 bit", or perhaps even wider, some
devices might only be able to work with 24-bit addresses).

If one is lucky enough, sometimes all of the various steps fade
away: perhaps Unit A deals only in 64-bit physical addresses in
the first place, and perhaps Unit B has a 64-bit address bus, so
that the "virtual address" in the C code *is* the physical address
and the mapping for Unit B is 1-to-1 as well. In this case, all
the intermediate steps drop out. But in principle, this is how
the task is normally accomplished. Worse, none of the steps has
anything to do with Standard C, so the C Standard is no help.
 
V

viza

There must be an option to select the int/pointer size surely?

Use appropriate types. Try long, and maybe long long.
Many appls would be quite happy to stay with 32-bit pointers; 64-bit
ones would just waste memory, bandwidth and performance.

If the registers are that big, then you waste more time converting up and
back. Also, when you run 32 but apps on amd64 (IA64T or AMD64) it is
also slowed by not using the new registers, and the less efficient
calling convention. If you want to design a system that uses the new
features but saves a bit of space by using smaller pointers you will
probably have to write your own compiler.
For my main appl, 64-bit data (ie. 64-bit moves) would help
tremendously, but if all my data doubled in size then I'm back where I
started.

memcpy() etc. should already be optimised to use the biggest size it can.
 
S

santosh

viza said:
On Tue, 17 Jun 2008 15:33:39 +0000, Bartc wrote:


If the registers are that big, then you waste more time converting up
and back. Also, when you run 32 but apps on amd64 (IA64T or AMD64) it
is also slowed by not using the new registers, and the less efficient
calling convention. If you want to design a system that uses the new
features but saves a bit of space by using smaller pointers you will
probably have to write your own compiler.

Also, in a typical program the number of pointer objects is much less
than the number of data objects. So any space saved by retaining 32 bit
pointers is not likely to make a significant difference.

<snip>
 
B

Bartc

santosh said:
Also, in a typical program the number of pointer objects is much less
than the number of data objects. So any space saved by retaining 32 bit
pointers is not likely to make a significant difference.

One of my structs would increase from 16-bytes to at least 24-bytes; that's
one pointer and one length needing to be doubled. Because 24 is 'odd' it
would probably be extended to 32-bytes. Arrays of this struct would be
double the size for no good reason if the total of all data is below 2GB.

I would imagine that for many programs in 64-bits, the machine would spend
much of it's time pushing around pointers where the top half is zero. Or,
where it would previously push 2 32-bit params for a function, it would now
have to push 2 64-bit params to satisfy the stack width. Again lots of zeros
being moved about. It could have pushed those 2 32-bit values, if
consecutive, in one instruction.
 
B

Barry Schwarz

thanks! this is really what was looking for !

that code invokes undefined behavior. I've already explained to Bart
why, but he doesn't seem to appreciate my advice.
You can do this:

#include <stdio.h>

int send(char *str);

int main(void) {
char s[512];
sprintf(s, "p", malloc(1024));

Did you mean %p?
send(s);
return 0;
}

int send(char *str) {
void *p;
sscanf(str, "%p", &p);
free(p);
return 0;
}

Or you can use (u)intptr_t.

However, all these examples use pointers in a way or another, I
suspect your homework question was made up by someone who doesn't
really know C.


Remove del for email
 

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,800
Messages
2,569,657
Members
45,411
Latest member
CarmaStarn
Top