address of list elements

Started by m35, June 20, 2007, 07:06:32 PM

Previous topic - Next topic

m35

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?

rickyboy

#1
Have you tried using newLISP arrays (instead of lists)?



Don't know if you'll fair better -- just guessing.  Good luck.  --Rick
(λx. x x) (λx. x x)

Lutz

#2
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 ;)

m35

#3
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.