Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28988 Discussions

string termination difference 11.1 vs XE2011

jeremy_h
New Contributor I
948 Views
In this program:

program Console1
use KERNEL32
implicit none

! Note space-terminated strings:
character*25 zinisection /'system_d '/
character*25 zkeywd /'systemtype '/
character*25 zkeywd_def /'unknown '/
character*25 zvalue
character*25 zinifile /'\\data\\pms.ini '/
integer*4 inumchar, isize
zvalue(1:)=' '
isize=25

inumchar=GetPrivateProfileString(
* zinisection,
* zkeywd,
* zkeywd_def,
* zvalue,
* isize,
* zinifile
* )
end program Console1


Compiled under 11.1 060 or 065, this windows call works with space-terminated strings. Under XE2011, it fails unless the strings are properly null-terminated. (BTW I tried all the calling conventions).

This is not great code, but there is a lot of it and it has worked for decades, including under Compaq and v11.1. If we have overlooked a switch or some magic that makes this work under XE2011, please advise.

0 Kudos
15 Replies
anthonyrichards
New Contributor III
948 Views
You omit to say what 'fails' means.
Fails to link?
Fails with an execution error?
Fails by returning an unusual value for 'inumchar'?
Please expand.

Your snippet works in CVF returning, a value of '7' for inumchar.
Note that all your character strings will end with more than one blank character anyway as they are 25 characters long, longer than any string you define at the start.
0 Kudos
jeremy_h
New Contributor I
948 Views
Thanks for looking, I spent an hour wordsmithing that and yet did not mention that the code links and runs but does not retrieve the profilestring under XE2011, but does under CVF and v11.1. (Obviously, one needs to match the params to an actual INI file).

Obviously, it is not this single call that worries me, it is the apparently different string termination handling between compilers. Our system is large (compared to the staff, anyway) and string values enter from thousands of sources and result in thousands of calls in hundreds of modules.
0 Kudos
anthonyrichards
New Contributor III
948 Views
So, go back to good old 11.1 maybe?
0 Kudos
garylscott1
Beginner
948 Views

The particular API requires null terminated strings. A space is not a "termination" character in Fortran or C. It likely only worked before because the C procedure found nulls by accident, likely following the string. The code is incorrect if it does not take explicit action to ensure a null character is present in the appropriate location within the allocated string buffer (not after it).

0 Kudos
mecej4
Honored Contributor III
948 Views
Getting XE2011 to work correctly by passsing null-terminated strings to GetPrivateProfileString turns out to be a bit of a problem, too. Here is a slightly altered version

[fortran]      program Console1
use KERNEL32
implicit none

character*25 zinisection /'Configuration'/
character*25 zkeywd /'Entry'/
character*25 zkeywd_def /'unknown'/
character*25 zvalue
character*25 zinifile /'langpms.ini'/
integer*4 inumchar, isize
zvalue(1:)=' '
isize=25

zinisection=TRIM(zinisection)//''C
zkeywd=TRIM(zkeywd)//''C
zvalue=TRIM(zvalue)//''C
zkeywd_def=TRIM(zkeywd)//''C
zinifile=TRIM(zinifile)//''C

inumchar=GetPrivateProfileString(
* zinisection,
* zkeywd,
* zkeywd_def,
* zvalue,
* isize,
* zinifile
* )
write(*,'(1x,I3,"|",A,"|")')inumchar,zvalue
end program Console1
[/fortran]
which, when used with this INI file

[bash][BEDW Ver 9.99, Mar 16 2012 15:34:12]
Exec dir=C:editorsBEDW
Config dir=C:EDITORSBEDWCONFIG
Name=Norman Schwartzkopf
Initials=NS
Company=USArmy
Swap dir=s:Temp
[Configuration]
Entry=SeVeNs
[/bash]
gives, with IFORT 11.1.067 and XE2011 on XP-32:

[bash]   6|SeVeNs                   |

The null-termination has to be done properly, and it looks as if you will need to spend quite a bit of time if you have lots of strings in your code passed this way.
[/bash]
0 Kudos
Andrew_Smith
Valued Contributor I
948 Views

Does //'' really append a null character, I would think that was appending an empty string, ie. a no effect at all.

0 Kudos
mecej4
Honored Contributor III
948 Views
Quite right, as I found on further checking. I remembered that sometime ago I used another compiler that use this funny way of adding a null -- in essense saying to itself, "this is so silly that he probably wants to do null termination". However, the present compiler does not. I have edited #5 to fix this.
0 Kudos
Steven_L_Intel1
Employee
948 Views
I think you meant to use //''C

The "C" is critical here.
0 Kudos
jeremy_h
New Contributor I
948 Views
I appreciate everyone's input here. The attraction of XE 2011 is the list file support. But this can wait.

I have read several Dr Fortran posts that the compiler is being gradually improved, and that blatantly nonconforming code will not be supported. I can't fault that. However, "proper" string termination for code that has worked for years is a tough sell to the boss right now. We will have to cross that bridge sooner or later, but not on this year's budget.
0 Kudos
Steven_L_Intel1
Employee
948 Views
If you believe you have been null-terminating strings by appending '', then your code does not work - it just seems to - maybe - sometimes.
0 Kudos
mecej4
Honored Contributor III
948 Views
It also follows that, if "blank-terminated strings" have been "working", either the failures were infrequent enough to be noticed, or the consequences of wrong results returned by this particular API call are insignificant.

If either of these conditions is not true -- XE2011 showed that the first is not true any more--, the code needs to be fixed.
0 Kudos
anthonyrichards
New Contributor III
948 Views
String="abcdefg"c
is turned into a null-terminated (by adding CHAR(0)) string by the compiler during cmpilation.
It only does this because it recognises what comes before the 'C' as a character string.
You can turn
string1="abcdefg"

into a null terminated string by using

string2=trim(string1)//char(0)

provided that string1 is not already filled, otherwise the extra null character cannot be added to the end of it.

0 Kudos
jeremy_h
New Contributor I
948 Views
Once again I appreciate the help. The code is wrong, no doubt, but also the code worked thru 11.1, and the baseline is the result of scores of developers working over decades on a resulting product that is very large and complex compared to size of the support staff. That is the attraction and the burden of "legacy code". The suggestions are all great fixes - but we don't have the manpower to do what needs to be done right now.

So, for now, I just wanted to thank everyone and we are retiring this issue until we can afford to take it on.
0 Kudos
Steven_L_Intel1
Employee
948 Views
I can verify that character variables in 11.1 had a NUL character after the last character of the variable, but in 12.1 they are closely packed. I knew that we had traditionally put a NUL at the end of character literal constants but was unaware that the compiler did this for variables.

Of course, as noted in this thread, code that relied on the value of the character after the variable is just plain wrong, and we have historically not shied away from making changes that break incorrect programs, no matter how many years had gone by. I'm not sure what prompted this change and will ask the developers, but don't get your hopes up of the change being reversed.
0 Kudos
Steven_L_Intel1
Employee
948 Views
I determined that the difference was that 11.1 4-byte aligned the character variables, leaving zeroes typically in the unused bytes, and 12.0 packs the variables without padding. It's just like other uses of uninitialized data - anything that changes teh memory layout can reveal or hide an error.
0 Kudos
Reply