address of list elements

For the Compleat Fan
Locked
m35
Posts: 171
Joined: Wed Feb 14, 2007 12:54 pm

address of list elements

Post by 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.

Code: Select all

(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:

Code: Select all

> (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
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Post by rickyboy »

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
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

* 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.

Code: Select all

> (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)))
"\0000[\176\0000[\128\0000[\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:

Code: Select all

>  (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
Posts: 171
Joined: Wed Feb 14, 2007 12:54 pm

Post by m35 »

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?

Code: Select all

(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

Code: Select all

(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.

Locked