NXC - addressOf and pointers
-
- Posts: 100
- Joined: 27 Dec 2010, 19:10
NXC - addressOf and pointers
I suspect my question may have been covered but doing a search, I didn't find an answer. I'd like to pass to
a function, an address of a variable, and have the function set the variable to a value. I think I understand
that NXC doesn't support pointers, but I did find addressOf(), which allows me to pass in the address. And
there is the function memcpy (variant dest, variant src, byte num). But, the help says that byte num, i.e.
the number of bytes copied, is ignored. This sounds like it could corrupt memory that I do not want changed.
Also, are dest and src, memory addresses, or variable names? The wording in the help left me suspect. In NXC,
is there a function like memcpy(), where the number of bytes to be copied, can be specified. Thanks for any
help. And if I missed an existing discussion about this, I apologize for taking people's time.
a function, an address of a variable, and have the function set the variable to a value. I think I understand
that NXC doesn't support pointers, but I did find addressOf(), which allows me to pass in the address. And
there is the function memcpy (variant dest, variant src, byte num). But, the help says that byte num, i.e.
the number of bytes copied, is ignored. This sounds like it could corrupt memory that I do not want changed.
Also, are dest and src, memory addresses, or variable names? The wording in the help left me suspect. In NXC,
is there a function like memcpy(), where the number of bytes to be copied, can be specified. Thanks for any
help. And if I missed an existing discussion about this, I apologize for taking people's time.
Re: NXC - addressOf and pointers
in NXC you can't pass a pointer or an address of a variable to a function or a procedure, but you may pass the variable (sort of) "by reference":
void myFunction (int & myVar) {...}
notice the "&" between variable type and variable name.
It's use is like in C++.
void myFunction (int & myVar) {...}
notice the "&" between variable type and variable name.
It's use is like in C++.
-
- Posts: 175
- Joined: 28 Dec 2011, 13:07
- Location: Gelderland, Netherlands
- Contact:
Re: NXC - addressOf and pointers
So can you pass around "function pointers"? That is, jump to a label or subroutine "by reference".
Something like
Or
Something like
Code: Select all
foo:
mov bar foo
jmp bar
Code: Select all
subroutine foo
add someresult 1 1
return
ends
mov bar foo
call bar
-- Pepijn
http://studl.es Mindstorms Building Instructions
http://studl.es Mindstorms Building Instructions
Re: NXC - addressOf and pointers
short answer: no.
long answer: no, because no stack, no heap, no pointers, no pointer functionality on the clump, just faked "reference" functions (actually only temporary copies to global variables).
Although muntoo tried a little around faking pointers by arrays, but IIRC it was only tinkering^^ (no offense, muntoo ;) )
long answer: no, because no stack, no heap, no pointers, no pointer functionality on the clump, just faked "reference" functions (actually only temporary copies to global variables).
Although muntoo tried a little around faking pointers by arrays, but IIRC it was only tinkering^^ (no offense, muntoo ;) )
Last edited by HaWe on 10 Jan 2012, 13:52, edited 3 times in total.
-
- Posts: 175
- Joined: 28 Dec 2011, 13:07
- Location: Gelderland, Netherlands
- Contact:
Re: NXC - addressOf and pointers
So then, how are "reference functions" compiled to NBC?
-- Pepijn
http://studl.es Mindstorms Building Instructions
http://studl.es Mindstorms Building Instructions
Re: NXC - addressOf and pointers
(I wasn't already finished writing my post)(actually only temporary copies to global variables)
Re: NXC - addressOf and pointers
As was mentioned, code and data are very distinct. Each variable is defined in the dataspace. Each chunk of code is defined in the codespace. Never the twain shall cross. All subroutine calls involve compile-time CLUMP_ID references. A subroutine call requires both a CLUMP_ID (resolved at compile time) and a return address variable specific to the called subroutine. To return from a subroutine you need to use the called subroutine's return address variable.
The value of FOO is calculated by the compiler. It is not a dataspace variable that you can use with opcodes that manipulate dataspace variables. The value stored at run-time by the firmware VM in FOO_RET is where code execution returns to when the subret opcode is executed in FOO.
As Doc kindly described, NXC fakes reference types by coping by value into a function and then copying by value back out of the function (unless the reference type is const, in which case it skips the copy out). Which also means unlike real references, if you modify the value inside a function and some other routine is executing simultaneously and it reads the value of the variable passed "by reference" into the other routine it will have its old value until the function call returns.
The ability to grab the address (relative) of a variable does allow you to directly modify that variable using IOMapWrite functionality. You would write to the Command module IOMap with an offset that points into the memory buffer where all variables are stored. I think I posted a bit of code that showed how you can do that. But none of the opcodes work with that ability so everything would be really slow and ugly. I have actually started a bit of enhanced firmware code changes that would add support for pointers but it is not ready for prime time. If someone wants to experiment with this at the NBC level it might be possible to do some things and I would be happy to work with such a person outside these forums.
http://bricxcc.sourceforge.net/nbc/nxcd ... le.html#a0
John Hansen
Code: Select all
subcall FOO, FOO_RET
Code: Select all
subroutine FOO
subret FOO_RET
ends
As Doc kindly described, NXC fakes reference types by coping by value into a function and then copying by value back out of the function (unless the reference type is const, in which case it skips the copy out). Which also means unlike real references, if you modify the value inside a function and some other routine is executing simultaneously and it reads the value of the variable passed "by reference" into the other routine it will have its old value until the function call returns.
The ability to grab the address (relative) of a variable does allow you to directly modify that variable using IOMapWrite functionality. You would write to the Command module IOMap with an offset that points into the memory buffer where all variables are stored. I think I posted a bit of code that showed how you can do that. But none of the opcodes work with that ability so everything would be really slow and ugly. I have actually started a bit of enhanced firmware code changes that would add support for pointers but it is not ready for prime time. If someone wants to experiment with this at the NBC level it might be possible to do some things and I would be happy to work with such a person outside these forums.
http://bricxcc.sourceforge.net/nbc/nxcd ... le.html#a0
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
http://bricxcc.sourceforge.net/
-
- Posts: 100
- Joined: 27 Dec 2010, 19:10
Re: NXC - addressOf and pointers
Thank you for the ideas. I'm experimenting with your suggestions using
<
reladdressOf() (I'm using in main to get an address to pass to a function and in the called function)
and
SysIOMapReadByID(read_args); (I'm using in the called function)
SysIOMapWriteByID(write_args); (I'm using in the called function)
>
from ideas shown in ex_reladdressof.nxc. I'm using similar code except have reladdressOf(unsigned long)
rather than reladdressOf(char array). It seems to meet my needs. I'll post my code to this topic after I test
it some more. It may help someone else.
Thanks again.
<
reladdressOf() (I'm using in main to get an address to pass to a function and in the called function)
and
SysIOMapReadByID(read_args); (I'm using in the called function)
SysIOMapWriteByID(write_args); (I'm using in the called function)
>
from ideas shown in ex_reladdressof.nxc. I'm using similar code except have reladdressOf(unsigned long)
rather than reladdressOf(char array). It seems to meet my needs. I'll post my code to this topic after I test
it some more. It may help someone else.
Thanks again.
Re: NXC - addressOf and pointers
You might also want to look at FlattenVar and UnflattenVar along with ByteArrayToStr and StrToByteArray. These functions will help you convert back and forth between an array of bytes and a variable.
John Hansen
John Hansen
Multi-platform LEGO MINDSTORMS programming
http://bricxcc.sourceforge.net/
http://bricxcc.sourceforge.net/
-
- Posts: 100
- Joined: 27 Dec 2010, 19:10
Re: NXC - addressOf and pointers
Here is my test code. I'm able to pass the addresses of 2 unsigned long variables to a function, that then sets
their values and returns. I display the variable values before and after the function call, and it looks okay.
Next step is to add the code to my dancing robots doing BT comm, and that will be the real test.
their values and returns. I display the variable values before and after the function call, and it looks okay.
Next step is to add the code to my dancing robots doing BT comm, and that will be the real test.
Code: Select all
// File iomap_write_08.nxc
// Created by: hdrake, TabbyCat Robots 2012Jan12
// The called function., that writes into addresses passed to it.
bool bt_receive_remote_number(unsigned char queue_id,
bool clear_queue,
unsigned long msg_addr,
unsigned long msg_type_addr);
task main()
{
// A design decision is that all variables that are passed to a called function,
// by their address, will be unsigned long. Two reasons for this. 1. To
// reduce the amount of my testing. 2. To reduces chances of making a mistake
// through brainfade, e.g. read_args.Count will always be equal = 4.
// After control is passed back to the calling function, then the value may be
// assigned to a different variable type.
// The following 2 variables are used for passing back values from the called
// function.
unsigned long received_msg;
unsigned long received_type;
// The following 2 addresses are used for the passing.
unsigned long received_msg_addr;
unsigned long received_type_addr;
// The following 3 addresses are used for my testing only, not needed in final
// code.
unsigned long msg_data_addr;
unsigned long data_type_addr;
unsigned long xger_id_addr;
unsigned short msg_data;
unsigned char data_type;
unsigned char xger_id;
bool bt_receive_status;
xger_id = 5;
// For testing assign an arbitrary values to variables, that will be assigned
// values in the called function.
received_msg = 0;
received_type = 0;
// For testing, assign initial values to variables, that be assigned returned
// values.
msg_data = 0x7fed;
data_type = 31;
xger_id_addr = reladdressOf(xger_id);
received_msg_addr = reladdressOf(received_msg);
received_type_addr = reladdressOf(received_type);
msg_data_addr = reladdressOf(msg_data);
data_type_addr = reladdressOf(data_type);
// Display the starting values.
TextOut(0, LCD_LINE1, FormatNum("%x", xger_id_addr));
TextOut(15, LCD_LINE1, FormatNum("%x", xger_id));
TextOut(30, LCD_LINE1, FormatNum("%x", received_msg_addr));
TextOut(45, LCD_LINE1, FormatNum("%x", received_msg));
TextOut(60, LCD_LINE1, FormatNum("%x", received_type_addr));
TextOut(75, LCD_LINE1, FormatNum("%x", received_type));
TextOut( 0, LCD_LINE2, FormatNum("%x", msg_data_addr));
TextOut(20, LCD_LINE2, FormatNum("%x", msg_data));
TextOut(48, LCD_LINE2, FormatNum("%x", data_type_addr));
TextOut(68, LCD_LINE2, FormatNum("%x", data_type));
// Call a function that will assign values to variables, local to this, the
// calling function.
bt_receive_status = bt_receive_remote_number(xger_id,
TRUE,
received_msg_addr,
received_type_addr);
// Assign the returned values to variables of different data types.
msg_data = received_msg;
data_type = received_type;
// As part of testing, see if any addresses change.
received_msg_addr = reladdressOf(received_msg);
msg_data_addr = reladdressOf(msg_data);
data_type_addr = reladdressOf(data_type);
// Display values after the function call, and subsequent assignments.
TextOut( 0, LCD_LINE6, FormatNum("%x", received_msg_addr));
TextOut(15, LCD_LINE6, FormatNum("%x", received_msg));
TextOut( 0, LCD_LINE7, FormatNum("%x", msg_data_addr));
TextOut(20, LCD_LINE7, FormatNum("%x", msg_data));
TextOut(48, LCD_LINE7, FormatNum("%x", data_type_addr));
TextOut(68, LCD_LINE7, FormatNum("%x", data_type));
until(ButtonPressed(BTNCENTER, TRUE));
} // End of - task main()
bool bt_receive_remote_number(unsigned char queue_id,
bool clear_queue,
unsigned long msg_addr,
unsigned long msg_type_addr)
{
bool bt_op_succeeds;
// Again, the variable involved in the transfer are unsigned long. See note
// in main.
unsigned long received_data;
unsigned long received_data_type;
unsigned long received_data_addr;
unsigned long received_data_type_addr;
IOMapReadByIDType read_args;
IOMapWriteByIDType write_args;
// In the real code the folowing 3 values would be from a BT operation.
received_data = 0xba7e;
received_data_type = 2;
bt_op_succeeds = TRUE;
received_data_addr = reladdressOf(received_data);
received_data_type_addr = reladdressOf(received_data_type);
TextOut( 0, LCD_LINE4, FormatNum("%x", received_data_addr));
TextOut(20, LCD_LINE4, FormatNum("%x", received_data));
TextOut(48, LCD_LINE4, FormatNum("%x", received_data_type_addr));
TextOut(68, LCD_LINE4, FormatNum("%x", received_data_type));
// Read a value, to be transferred, into the SysIOMap buffer.
read_args.ModuleID = CommandModuleID;
read_args.Offset = CommandOffsetMemoryPool + received_data_addr;
read_args.Count = 4;
SysIOMapReadByID(read_args);
// Write the value back to the address passed in. Some magic has occurred,
// that I don't understand, such that the byte count to be written doesn't
// need to be specified. (Did the Count from the read get stored somewhere?)
write_args.ModuleID = CommandModuleID;
write_args.Offset = CommandOffsetMemoryPool + msg_addr;
write_args.Buffer = read_args.Buffer;
SysIOMapWriteByID(write_args);
read_args.ModuleID = CommandModuleID;
read_args.Offset = CommandOffsetMemoryPool + received_data_type_addr;
read_args.Count = 4;
SysIOMapReadByID(read_args);
write_args.ModuleID = CommandModuleID;
write_args.Offset = CommandOffsetMemoryPool + msg_type_addr;
write_args.Buffer = read_args.Buffer;
SysIOMapWriteByID(write_args);
return bt_op_succeeds;
} // End of - bt_receive_remote_number()
// End of - File iomap_write_08.nxc
Who is online
Users browsing this forum: Semrush [Bot] and 5 guests