newLISP Fan Club

Forum => Anything else we might add? => Topic started by: m35 on June 20, 2007, 07:06:32 PM

Title: address of list elements
Post by: m35 on June 20, 2007, 07:06:32 PM
I'm working with a DLL that takes a char** as an argument (an array of char*). It would be nice it I could keep the strings being passed in a list, and just pack the addresses of those list elements.



e.g.(setq x '("a" "b" "c"))
(setq arg (eval (cons pack (cons (dup "ld" (length x)) (map address x)))))
(My_Dll_Func arg)


However, my tests don't suggest I'm getting the addresses of the list elements:



> (setq x '("a" "b" "c"))
("a" "b" "c")
> (address x)
4019592
> (address (x 0))
5341424
> (address (x 1))
5341424
> (address (x 2))
5341424
> (address (nth 0 x))
5341424
> (address (nth 1 x))
5341424
> (address (nth 2 x))
5341424
> (map address x)
(4044024 4044136 4044152)
> (map address x)
(4044152 4044136 4044024)
> (map address x)
(4044024 4044136 4044152)
>


Work-arounds I've considered:

* Put every string into a separate symbol so I can get the addresses.

* Pack every string into one big string, then get the address of this big string, and add the offsets of each substring.



Neither of these work-arounds make me very happy. Is there any better solution?
Title:
Post by: rickyboy on June 20, 2007, 07:32:49 PM
Have you tried using newLISP arrays (instead of lists)?



Don't know if you'll fair better -- just guessing.  Good luck.  --Rick
Title:
Post by: Lutz on June 20, 2007, 07:57:55 PM
Quote* Put every string into a separate symbol so I can get the addresses.

* Pack every string into one big string, then get the address of this big string, and add the offsets of each substring.


Either one would work. Only the symbol (variable) guarantees you a fixed addresss for the string contained. All other methods just get addresses of volatile memory objects. The symbol acts like a pointer to the string contained.


> (set 'V '(v1 v2 v3))
(v1 v2 v3)
> (map set V '("A" "B" "C"))
("A" "B" "C")

> (set 'char** (eval (append (cons pack (dup "lu" (length V))) V)))
"000[176000[128000[144" ; 3 32-bit addresses = 12 bytes

> (length char**) ; the length function works on binary contents
12

> (get-string (get-int (+ (address char**) 0)))
"A"
> (get-string (get-int (+ (address char**) 4)))
"B"
> (get-string (get-int (+ (address char**) 8)))
"C"
>


similar to your first approach, but the difference is that the strings are referenced via the symbols v1,v2,v3. Symbols holding strings work like  C pointers.



Lutz



ps:
>  (append (cons 'pack (dup "lu" (length V))) V)
(pack "lululu" v1 v2 v3)
>


The quote before the pack isn't really required, but makes for better looking output ;)
Title:
Post by: m35 on June 21, 2007, 09:57:10 AM
Thanks Lutz, I guess I'll have to use a work-around.



But since I'm here, may I also propose an improvement to the (address) function? :)



Since the behavior of (address <list>) is currently undefined, could we add one (or both) of the following?
(address <list>) => [list of addresses of the list elements]

e.g.
> (setq x '("a" "b" "c"))
("a" "b" "c")
>(address x)
(4044152 4044136 4044024)
or(address <list> <index>) => [address of element at <index>]

e.g.
> (setq x '("a" "b" "c"))
("a" "b" "c")
>(address x 1)
4044136


Not all that important, but I thought I'd throw it out there.