Hi Raul,
The problem with %int or %dec is the sign. 0M zoned is -4, int or dec
report it as error.
I must be doing a very poor job of explaining myself, as this is now the
third time I'm explaining it in this thread, and frankly, it's not a
very complicated concept.
Pretend variables don't exist for a moment. Variables don't matter.
It's bytes in memory that matter.
Alan has this in the bytes in memory: x'F0F0F0F0F0F0F0F0D4'
What does that look like to you? If you think about it, it's zoned
decimal. The bytes exactly follow the rules of zoned decimal. Despite
the fact that it's in an alphanumeric field, it's truly a collection of
bytes that's intended to be a zoned decimal number.
Can you use %dec() or %int() to convert it to a numeric variable
reliably? Of course not!! The data isn't in text format, it's in zoned
decimal format! Sure, if you desire the output in integer format, you
could use %int() to make it an integer field -- but you have to tell RPG
that the data is ZONED DECIMAL not ALPHANUMERIC if you want that to
function properly. In other words, feeding the alphanumeric field into
%int() won't work. (And I can't see any value to %dec() in this
instance, since the data is *already* in decimal format).
So what do you want to do? Is the desired goal to run these bytes
through a routine that converts from x'F0F0F0F0F0F0F0F0D4' to
x'FFFFFFFD'? That's a large change, isn't it? It changes the field
from 9 bytes to 4 bytes. It changes the values of the bytes
dramatically. And, why would you want to do that? If the end result of
an 'integer' field is what's desired, sure... you can do that, but I'd
suggest coding it in RPG rather than C. i.e. first use a DS to view
that same memory as zoned, then use %int() to make it an integer. But,
I don't think the desired result is the integer (x'FFFFFFFD') format.
The data is already in a valid zoned decimal format. All you really
want to do is view that same memory as a zoned field instead of viewing
it as an integer field.
You don't need a complex API to convert the data from one format to
another because it's already in a useful format. Just view the memory as
zoned:
D char ds
D zoned 9s 0
When you read the field in, read it into the field named 'char', above.
Without any further work being done by the CPU, you can now read the
'zoned' field, and it's in zoned decimal format. The memory is
/already/ zoned decimal, and now you're viewing it as such instead of
viewing it as alphanumeric.
Or, if it's easier to call a routine, here's a 5-second routine that
simply copies the memory from any arbitrary point in memory to a zoned
decimal field:
p MakeZoned b
d MakeZoned pi 9s 0
d Input * value
D Zoned s 9s 0 based(input)
c return zoned
P E
That routine will run faster than the QXXZTOI routine because it's a
much simpler routine -- it just copies the memory, it doesn't have to do
the conversion.
Honestly, the routine you're calling, QXXZTOI is intended to work the
same way as RPG's %dec() BIF, except that it has fewer features than
%dec(). QXXZTOI can only accept input in zoned format, whereas %dec()
can accept input in many different formats.
When calling QXXZTOI from RPG, you really SHOULD prototype it like this:
D cvtZonedToInt pr 10i 0 extproc('QXXZTOI')
d cvtZone 9s 0 const
d cvtDigits 10i 0 value
d cvtFraction 10i 0 value
The only reason the C prototype doesn't use zoned decimal for the first
parameter is because C doesn't support zoned decimal as a data type.
Thus, if you're going to have a zoned decimal field in C, you have to
store the raw bytes in a character field. RPG doesn't have that
limitation, it supports zoned natively.
The purpose of the API isn't to convert from character to zoned, it's to
convert from zoned to integer. Since your data isn't in character/text
format to begin with, it's actually in zoned format to begin with, it
just HAPPENS to work for you. You've coded the parameters like this
instead:
D cvtZonedToInt pr 10i 0 extproc('QXXZTOI')
d cvtZone * value
d cvtDigits 10i 0 value
d cvtFraction 10i 0 value
By prototyping it this way, you've basically told it to do exactly what
the data structure did. You've told it to view the area of memory
addressed by the pointer as zoned decimal -- and therefore, it's viewing
the character field as zoned instead of character. But, this API has
the extra overhead of ALSO converting it to integer, which isn't really
needed in this instance. Therefore, the API isn't really the right tool.
To put it in RPG terms (though, I'm not sure why, since you all seem to
really want to do this in C code) the QXXZTOI API with the pointer
parameter on the prototype does this:
D char ds
D zoned 9s 0
D int s 10i 0
/free
// read data into "char"
int = %int(zoned);
That's all the API does. All I'm saying is that the last step of
converting to integer is not necessary. You really want a decimal
field, not an integer. So this is what you really want to do:
D char ds
D zoned 9s 0
/free
// read data into "char".
// use "zoned"
I think that's all the OP needs is to get it into zoned.
However, in my original message, I suggested that if for some reason the
OP wants the extra funcitonality of having it converted to another data
type such as integer, date, or packed, he can still call the %int, %dec,
or %date BIF. That doesn't mean that you can omit the data structure
part and only use %dec(), Raul. Just that if these other formats are
needed, they ARE available after you've already converted it to zoned.
I'd rather see the code written in pure RPG rather than calling a C
function. Just my opinion. I work in C frequently, and I think
everyone knows that I don't hesitate to call C routines when I need them
-- but I just don't see how one is needed in this case.
As an Amazon Associate we earn from qualifying purchases.