It seems like uninitialized variables in PROC FCMP get a default length of 33 bytes. Consider the following demonstration code:
OPTIONS INSERT = (CMPLIB = WORK.FCMP);
PROC FCMP
OUTLIB = WORK.FCMP.FOO
;
FUNCTION FOO(
BAR $
);
* Assign the value of BAR to the uninitialised variable BAZ;
BAZ = BAR;
* Diagnostics;
PUT 'BAR IS ' BAR;
PUT 'BAZ IS ' BAZ;
* Return error code;
IF
LENGTH(BAZ) NE LENGTH(BAR)
THEN
RETURN(0)
; ELSE
RETURN(1)
;
ENDSUB;
RUN;
DATA _NULL_;
X = 'shortstring';
Y = 'exactly 33 characters long string';
Z = 'this string is somewhat longer than 33 characters';
ARRAY STRINGS{*} _CHARACTER_;
ARRAY RC{3} 8 _TEMPORARY_;
DO I = 1 TO DIM(STRINGS);
RC[I] = FOO(STRINGS[I]);
END;
RUN;
Which, with my site's installation (Base SAS 9.4 M2) prints the following lines to the log:
BAR IS shortstring
BAZ IS shortstring
BAR IS exactly 33 characters long string
BAZ IS exactly 33 characters long string
BAR IS this string is somewhat longer than 33 characters
BAZ IS this string is somewhat longer th
This is likely related to the fact that PROC FCMP, like DATA steps, cannot allocate variable lengths dynamically at runtime. However, it's a little confusing, because it does dynamically allocate variable lengths for parameters. I'm assuming that there is a separate "initialization" phase for PROC FCMP subroutines, during which the length of values passed as arguments are determined and parameter variables which must hold those values are initialized to the required length. However, the length of variables defined only within the body of the subroutine can only be discovered at runtime, when memory has already been allocated. So prior to runtime (whether at compile-time or my hypothetical "initialization" phase), memory is allocated to these variables with an explicit LENGTH statement if present, and otherwise falls back to a default of 33 bytes.
Now what's really interesting is that PROC FCMP is as smart as can be about this -- within the strict separation of initialization/runtime stages. If, in the body of the subroutine, a variable A
has an explicitly defined LENGTH, and then another uninitialized variable B
is assigned a function of A
, then B
is set to the same length as A
. Consider this modification of the above function, in which the value of BAR
is not assigned directly to BAZ
, but rather via the third variable QUX
, which has an explicitly defined LENGTH
of 50 bytes:
OPTIONS INSERT = (CMPLIB = WORK.FCMP);
PROC FCMP
OUTLIB = WORK.FCMP.FOO
;
FUNCTION FOO(
BAR $
);
LENGTH QUX $ 50;
QUX = BAR;
* Assign the value of BAR to the uninitialised variable BAZ;
BAZ = QUX;
* Diagnostics;
PUT 'BAR IS ' BAR;
PUT 'BAZ IS ' BAZ;
* Return error code;
IF
LENGTH(BAZ) NE LENGTH(BAR)
THEN
RETURN(0)
; ELSE
RETURN(1)
;
ENDSUB;
RUN;
DATA _NULL_;
X = 'shortstring';
Y = 'exactly 33 characters long string';
Z = 'this string is somewhat longer than 33 characters';
ARRAY STRINGS{*} _CHARACTER_;
ARRAY RC{3} 8 _TEMPORARY_;
DO I = 1 TO DIM(STRINGS);
RC[I] = FOO(STRINGS[I]);
END;
RUN;
The log shows:
BAR IS shortstring
BAZ IS shortstring
BAR IS exactly 33 characters long string
BAZ IS exactly 33 characters long string
BAR IS this string is somewhat longer than 33 characters
BAZ IS this string is somewhat longer than 33 characters
It's likely that this "helpful" behavior is the cause of confusion and differences in the previous answers. I wonder if this behavior is documented?
I'll leave it as an exercise to the reader to investigate exactly how smart SAS tries to get about this. For example, if an uninitialized variable gets assigned the concatenated values of two other variables with explicitly assigned lengths, is its length set to the sum of those of the other two?