×
The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.
Hello,
I have the following RPG program that is calling a C function, but all i get
back is a Null each time. If i put it in debug mode i can see that the value
of chkdigit is correct, but then, when i get it back in my RPG, the value is
NULL.
In your code, you declare two variables that are local to the function. A
one character variable called "chkdigit" and a pointer to a character
called "check_bit"
char* Pr_ChkDigit(char *str)
{
char chkdigit;
char* check_bit;
At the time that these start up, what are they set to? Nothing in
particular. C doesn't initialize variables, so they could really have any
value.
Most of the time, they'll probably be 0x00, but you can't be sure. That
also means that the pointer will be NULL, since a pointer that's set to
all zeroes is NULL.
Now look at the code that uses them:
//Calcuations
// Get checkbit from the Mapping Matrix
chkdigit=reverse_map(c1,c2) ;
Okay, this changes the value of chkdigit.
*check_bit = chkdigit;
Now, this copies the value of chkdigit to whatever memory is stored where
"check_bit" points to. Where does check_bit point to? Most of the time,
it'll be NULL. Sometimes it might actually point to real memory, in which
case you've just corrupted that memory, because you haven't allocated
anything to it!
return check_bit;
And now you're returning the pointer, which will usually be NULL.
It might be tempting to return &chkdigit instead. (The address of the
chkdigit variable) but that would also be wrong, since this is the last
statement of your function, and the memory that was allocated to the
chkdigit variable will be deallocated before control is returned to the
caller.
IMHO, it would make more sense to return a character than to return a
pointer! That way, you won't have to worry about the memory being freed
up.
If you DO want to work with a pointer for some reason, I strongly
recommend passing that pointer in as a parameter so that it refers to the
caller's storage instead of the something allocated by the function
itself. That way, you don't have to worry about when it gets allocated or
deallocated. Make that the caller's responsibility -- it gives the caller
the option of using automatic storage or static storage or whatever they
want to use.
Now let's talk about your RPG program :)
D Pr_ChkDigit PR * ExtProc('Pr_ChkDigit')
D * Options(*string) value
D Wrk_Str s 36A
D Wrk_Null s 1A Inz(X'00')
D Wrk_ChkDigit s 1A
D Ptr_ChkDigit s * INZ(%ADDR(Wrk_ChkDigit))
/Free
Wrk_Str = '70500607050AEI02x' + Wrk_Null;
Ptr_ChkDigit = Pr_ChkDigit(%Addr(Wrk_Str));
Dsply Wrk_ChkDigit;
*InLr = *on;
/End-Free
(Wow, is that hard to read. What happened to the spaces that put things
into the right columns?)
The options(*string) on the prototype says to the compiler "I want you to
automatically add a x'00' to the end of the string when you pass it."
Then, what's the very first thing you do in your code? You manually add a
x'00'. You don't need to do that! You just told the compiler to do it for
you!!
In the next line of code, you call the PR_ChkDigit() function and you tell
it to assign the result to your pointer called Ptr_ChkDigit. Okay, so why
did you assign the address of Wrk_ChkDigit to the pointer in the D-specs,
if the very first thing in your program is to change that value to
something else?!
Not only that, but the DSPLY that occurs on the next line won't do you any
good because Wrk_ChkDigit no longer has any relationship to Ptr_ChkDigit.
It doesn't make any sense!
You probably intended to do the following:
D Ptr_ChkDigit s *
D Wrk_ChkDigit s 1A based(Ptr_ChkDigit)
There's a BIG difference. When you initialize a pointer to the address of
a field, RPG allocates memory for that field, and then sets the pointer to
the address of the memory it allocated.
When you use BASED, you say "this field is always located in the memory
that I point to with the basing pointer". RPG won't allocate any memory
to the field, because you can change where the field points to, so
allocating memory wouldn't make sense.
Basically, BASED is like dereferencing a pointer in C. In other words,
these two sets of code do the same thing:
D Ptr_ChkDigit s *
D Wrk_ChkDigit s 1A based(Ptr_ChkDigit)
Ptr_ChkDigit = %alloc(1);
Wrk_ChkDigit = something;
dealloc Ptr_ChkDigit;
is the same as:
char *ptr_chkdigit;
ptr_chkdigit = malloc(1);
*ptr_chkdigit = something;
free(ptr_chkdigit);
And the following two code snippets are likewise the same:
D Ptr_ChkDigit s * inz(%addr(WrkChkDigit))
D Wrk_ChkDigit s 1A
Wrk_ChkDigit = something;
is the same as:
char wrk_chkdigit;
char *ptr_chkdigit;
ptr_chkdigit = &wrk_chkdigit;
wrk_chkdigit = something;
Does that help?
As an Amazon Associate we earn from qualifying purchases.