Newsgroup: it.comp.lang.delphi
Titolo: Conversione puntatori da C a Delphi

Ho dovuto convertire tre funzioni da C a Delphi, il problema è che le
funzioni in C utilizzavano i puntatori a manetta. Il C lo conosco un
pochino, visto che l'ho dovuto imparare 6 anni fa in 15 gg e poi di corsa a
mettere le mani su programmi di bolle-fatture, quindi siccome i puntatori
venivano utilizzati solo per la copia delle stringhe, come argomento li ho
visti molto di sfuggita.
Queste funzioni, leggono da un'archivio i double scritti in un formato più o
meno proprietario e li convertono in double normali.
Non c'è un modo sicuro per capire se sono giuste in quanto il comportamento
varia a seconda della grandezza del numero. Mi capitava che funzionassero e
poi con numeri grandi sballavano. Questa versione sembra giusta. Qualche
anima pia, riesce a darmi una controllata soprattutto nei cicli in cui fà la
differenza il fatto che ad esempio sia scritti i++ piuttosto che ++i.
Grazie
******** FUNZIONI C ***************
struct decimal                 /* the structure on an UNPACKED decimal */
      { short dec_exp;         /* the exponent */
        short dec_pos;         /* is the value "positive", flag */
        short dec_ndgts;       /* the number of valid digits in dec_dgts */
        char  dec_dgts[DECSIZE];       /* the digits, base 100 */
      };
lddecimal (cp, len, dp)
unsigned char *cp;
int len;
dec_t *dp;
{
unsigned char buffer[DECSIZE + 1];
register count;
register unsigned char *digits;
   if (*cp == 0)           /* special case of DECNULL */
   {
      dp->dec_pos = DECPOSNULL;
      dp->dec_exp =  0;
      dp->dec_ndgts = 0;
      return (0);
   }
   /*
   ** make a copy of the number's mantissa
   */
   if (--len > DECSIZE)    /* internal format has only DECSIZE digits */
       len = DECSIZE;
   memcpy (buffer, cp + 1, len);
   /*
   ** check for negative number and set sign
   ** unpack exponent
   */
   if (*cp & 0x80)         /* true if number is positive */
   {
      dp->dec_pos = 1;
      dp->dec_exp = *cp - 0xC0;
   }
   else                    /* we have a negative number   */
   {
      comp100 (buffer, len);      /* take 100's complement */
      dp->dec_pos = 0;
      dp->dec_exp = 0xFF - (*cp) - 0xC0;
   }
   /*
   ** compute number of significant digits
   */
   cp = buffer + len;
   while (len > 0 && *--cp == 0)
      len--;
   dp->dec_ndgts = len;
   /*
   ** copy unpacked mantissa
   */
   digits = (unsigned char *)dp->dec_dgts;
   cp     = buffer;
   while (len-- > 0)
      *digits++ = *cp++;
   return (0);
}
dectoflt (dp, fltp)
dec_t *dp;
float *fltp;
{
double dbl;
int status;
   status = dectoreal (dp, &dbl, FLT_DIG);
   *fltp = dbl;
   return (status);
}
static dectoreal (dp, dblp, valid)
dec_t *dp;                      /* ptr to dec_t to convert */
double *dblp;                   /* ptr to double to hold converted value */
register int valid;             /* max number of significant digits to use
*/
{
register char *digits = dp->dec_dgts;
double dbl;
   if (valid > dp->dec_ndgts)      /* can't use more digits than exist */
       valid = dp->dec_ndgts;
   dbl = 0.0;                      /* initialize value */
   /*
   ** convert the mantissa
   */
   while (valid-- > 0)                     /* copy mantissa */
      dbl = (dbl + digits[valid]) / 100.0;
   if (dp->dec_pos == 0)                   /* set sign of mantissa */
      dbl = -dbl;
   /*
   ** convert the exponent
   */
   if (dp->dec_exp > 0)
   {
   register i = dp->dec_exp;
      while (i--)
         dbl *= 100.0;
   }
   else if (dp->dec_exp < 0)
   {
   register i = dp->dec_exp;
      while (i++)
         dbl /= 100.0;
   }
   /*
   ** copy value to user's area and you're done
   */
   *dblp = dbl;
   return (0);
}
/*
** form 100's complement of normalized value in buffer pointed at by cp.
** count is number of digits in buffer.
*/
static void comp100 (cp, count)
register unsigned char *cp;
register int count;
{
register int base;
   base = 100;
   cp += count;
   while (count--)
   {
      cp--;
      *cp = base - *cp;
      if (*cp > 99)
      {
         *cp -= 100;
         base = 100;
      }
      else
         base = 99;
   }
}
static dectoreal (dp, dblp, valid)
dec_t *dp;                      /* ptr to dec_t to convert */
double *dblp;                   /* ptr to double to hold converted value */
register int valid;             /* max number of significant digits to use
*/
{
register char *digits = dp->dec_dgts;
double dbl;
   if (valid > dp->dec_ndgts)      /* can't use more digits than exist */
       valid = dp->dec_ndgts;
   dbl = 0.0;                      /* initialize value */
   /*
   ** convert the mantissa
   */
   while (valid-- > 0)                     /* copy mantissa */
      dbl = (dbl + digits[valid]) / 100.0;
   if (dp->dec_pos == 0)                   /* set sign of mantissa */
      dbl = -dbl;
   /*
   ** convert the exponent
   */
   if (dp->dec_exp > 0)
   {
   register i = dp->dec_exp;
      while (i--)
         dbl *= 100.0;
   }
   else if (dp->dec_exp < 0)
   {
   register i = dp->dec_exp;
      while (i++)
         dbl /= 100.0;
   }
   /*
   ** copy value to user's area and you're done
   */
   *dblp = dbl;
   return (0);
}
dectodbl (dp, dblp)
dec_t *dp;
double *dblp;
{
   return (dectoreal (dp, dblp, DBL_DIG));
}
******************* FUNZIONI PASCAL ********************
procedure comp100(cp: PChar; count: Integer);
var base, Idx: Byte;
begin
  base := 100;
  Idx := Count;
  Dec(Count);
  while (Count >= 0) do
  begin
    Idx := Idx - 1;
    Byte(cp[Idx]) := base - Byte(cp[Idx]);
    if (Byte(cp[Idx]) > 99)
    then
    begin
      Byte(cp[Idx]) := Byte(cp[Idx]) - 100;
      base := 100;
    end
    else
      base := 99;
    Dec(Count);
  end;
end;
procedure lddecimal(cp: PChar; len: Integer; dp: Pdec_t);
const DECPOSNULL = -1;
  DECSIZE = 16;
var
  buffer: array [0..DECSIZE] of Char;
  count, Idx: Integer;
  digits: PChar;
begin
//  Len := 8;
  if Byte(cp[0]) = 0
  then
  begin
    dp^.dec_pos := DECPOSNULL;
    dp^.dec_exp := 0;
    dp^.dec_ndgts := 0;
    Exit;;
  end;
  Len := Len - 1;
 if (Len > DECSIZE)    (* internal format has only DECSIZE digits *)
 then
   Len := DECSIZE;
  CopyMemory(@buffer, cp + 1, Len);
   (*
   ** check for negative number and set sign
   ** unpack exponent
   *)
   if (Byte(cp[0]) and $80) <> 0         (* true if number is positive *)
   then
   begin
     dp^.dec_pos := 1;
     dp^.dec_exp := Byte(cp[0]) - $C0;
   end
   else                    (* we have a negative number   *)
   begin
     comp100(buffer, len);      (* take 100's complement *)
     dp^.dec_pos := 0;
     dp^.dec_exp := $FF - Byte(cp[0]) - $C0;
   end;
   (*
   ** compute number of significant digits
   *)
   len := len + 1;
   Idx := len - 1;
//   Idx := len;
   while (len > 0) and (Byte(Buffer[Idx]) = 0) do
   begin
     Dec(Idx);
     Dec(len);
   end;
   dp^.dec_ndgts := len;
   (*
   ** copy unpacked mantissa
   *)
   digits := @(dp^.dec_dgts);
   Idx := 0;
   while (len > 0) do
   begin
     digits[Idx] := Buffer[idx];
     Inc(Idx);
     Dec(Len);
   end;
end;
procedure dectoreal(dp: Pdec_t; dblp: PDouble; valid: Integer);
var digits: PChar;
  dbl: Double;
  i: Integer;
begin
//register char *digits = dp->dec_dgts; Che cavolo fa???
// register char *digits;
// digits = dp->dec_dgts;
   digits := @dp^.dec_dgts;
   if (valid > dp^.dec_ndgts)      (* can't use more digits than exist *)
   then
     valid := dp^.dec_ndgts;
   dbl := 0.0;                      (* initialize value *)
   (*
   ** convert the mantissa
   *)
   while (valid > 0) do                    (* copy mantissa *)
   begin
     Dec(valid);
     dbl := (dbl + Byte(digits[valid])) / 100.0;
   end;
   if (dp^.dec_pos = 0)                   (* set sign of mantissa *)
   then
     dbl := -dbl;
   (*
   ** convert the exponent
   *)
   if (dp^.dec_exp > 0)
   then
   begin
     i := dp^.dec_exp;
     while (i <> 0) do
     begin
       dbl := dbl * 100.0;
       Dec(i);
     end;
   end
   else if (dp^.dec_exp < 0)
   then
   begin
     i := dp^.dec_exp;
     while (i <> 0) do
     begin
       dbl := dbl / 100.0;
       Inc(i);
     end;
   end;
   (*
   ** copy value to user's area and you're done
   *)
   dblp^ := dbl;
end;
function dectoflt(dp: Pdec_t; fltp: PSingle): Integer;
const FLT_DIG = 6;
var
  dbl: Double;
  status: Integer;
begin
  dectoreal(dp, @dbl, FLT_DIG);
  fltp^ := dbl;
  Result := 0;
end;
procedure dectodbl(dp: Pdec_t; dblp: PDouble);
const DBL_DIG = 15;
begin
  dectoreal(dp, dblp, DBL_DIG);
end;

i++ vuol dire che prima utilizzi il valore il di i e poi lo incrementi,
++i invece è il contrario
es
x = 1
y= x++
allora x=2, y=1
mentre
x=1
y=++y
x=2, y=2
Ciao Enrico
Sam ha scritto nel messaggio ...


 mettere le mani su programmi di bolle-fatture[...]
Non mi metto a riscriverti il codice, perché richiederebbe troppo
tempo e andrebbe riadattato a dovere... tieni presente che, in C, non
esiste il passaggio per riferimento dei parametri, ma solo per valore.
Il passaggio per riferimento si simula con il passaggio del puntatore
ad una variabile.  Quindi laddove trovi qualcosa del tipo:
int funzione(unsigned char *p)
{
    if (*p <= 3) then
    {
       *p = *p + 1;
    }
    return *p + 2;
}
puoi tradurlo con:
function funzione(var p: Byte): Integer;
begin
  if p <= 3 then
    p := p + 1;
  Result := p + 2;
end;
Isola la parte di codice su cui hai maggiori difficoltà.

meno proprietario e li convertono in double normali.
Mmmhhh, sei sicuro che il formato sia proprietario ?
Googlando per "Packet Decimal" ho trovato molti thread interessanti:
http://snipurl.com/4dkp
ne e' un esempio.
Cioe', il mio ragionamento e': al di la' della difficolta intrinseca di un
sorgente c/c++ che fa largo uso di puntatori, cerca di capire qual'e' il
formato esatto dei dati memorizzati.
Se questo dovesse essere riconosciuto come un packet decimal, che e' un
formato pubblico, allora prendi e utilizza delle funzioni che gia' conosci e
sei in grado di modificare, scritte  magari anche in delphi. (googla per
packet record delphi)
Per quanto riguarda la tua domanda, non v'e' possibilita' di capire fino a che
punto le funzioni siano corrette, a meno di farle girare con un debugger... un
dato di fatto' pero' e' che non puoi permetterti di usare una funzione che
funziona per "numeri piccoli ma non per i numeri grandi"... ;)
Parlando di C/C++, ritengo che l'uso del preincremento (++pippo) sia foriero
piu' di confusione che di chiarezza di codice. (imho)
Ciao
-- 
Morde. 
(
mo...@despammed.com
)
M-List di icld: 
http://it.groups.yahoo.com/group/icld/

>     if (*p <= 3) then
Scusa, ovviamente il "then" non esiste, in C ! ;-)

Scusa, ovviamente il "then" non esiste, in C ! ;-)
Eh eh.. ti stavo preparando uno shampoo... meno male che ti sei auto corretto!
;-)


 ;-)
Uno shampoo a me sul C ?! stai rischiando la vita...

Uno shampoo a me sul C ?! stai rischiando la vita...
ah ah ah ... adoro il rischio e l'adrenalina !!!


> Isola la parte di codice su cui hai maggiori difficoltà.
Prima di tutto ringrazio tutti per la disponibilità ecco le parti che mi
incasinano la vita:
funzione lddecimal:
   Premesso che quando utilizzo io la funzione len E' SEMPRE minore o uguale
a DECSIZE
   if (--len > DECSIZE)    /* internal format has only DECSIZE digits */
       len = DECSIZE;
 penso basti che traduca con
len := len - 1;
 if (Len > DECSIZE)
 then
   Len := DECSIZE;
gli altri punti che ho il dubbio sono questi che è praticamente dove "gioca"
con i puntatori
   memcpy (buffer, cp + 1, len);
   cp = buffer + len;
   while (len > 0 && *--cp == 0)
      len--;
   dp->dec_ndgts = len;
   digits = (unsigned char *)dp->dec_dgts;
   cp     = buffer;
   while (len-- > 0)
      *digits++ = *cp++;
 tradotto in:
   len := len + 1;
   Idx := len - 1;
   while (len > 0) and (Byte(Buffer[Idx]) = 0) do
   begin
     Dec(Idx);
     Dec(len);
   end;
   dp^.dec_ndgts := len;
   digits := @(dp^.dec_dgts);
   Idx := 0;
   while (len > 0) do
   begin
     digits[Idx] := Buffer[idx];
     Inc(Idx);
     Dec(Len);
   end;
nella funzione:
dectoreal:
   while (valid-- > 0)                     /* copy mantissa */
      dbl = (dbl + digits[valid]) / 100.0;
   while (valid > 0) do                    (* copy mantissa *)
   begin
     Dec(valid);
     dbl := (dbl + Byte(digits[valid])) / 100.0;
   end;
   if (dp->dec_exp > 0)
   {
   register i = dp->dec_exp;
      while (i--)
         dbl *= 100.0;
   }
   else if (dp->dec_exp < 0)
   {
   register i = dp->dec_exp;
      while (i++)
         dbl /= 100.0;
   }
   if (dp^.dec_exp > 0)


 -- 

    memcpy (buffer, cp + 1, len);
Questo non fa che copiare "len" byte dentro buffer, dalla posizione
cp+1.
cp è un puntatore a carattere e in C vale l'aritmetica tra puntatori
(es.: addizione di uno scalare al puntatore).  I vettori di caratteri
"decadono" (a meno di tre condizioni specifiche[1]) in puntatori al
primo elemento.  Se hai, ad esempio:
char a[30];
e scrivi: *(a+2)
equivale a scrivere s[2], perché in questo caso "a" decade nel
puntatore al primo elemento, gli sommi 2 e ottieni l'elemento a[2].
[1] le tre circostanze specifiche che fanno eccezione sono l'uso
dell'operatore sizeof, l'uso dell'operatore & e l'inizializzazione di
un array di caratteri con un "literal".


Grazie