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

C Null char in format statment

andrew_4619
Honored Contributor II
2,504 Views

Hopefully an easy question, consider the code snip:

        character(20) :: gbuf
        write(gbuf,1) flt,char(0)
        1 format(f10.3,A)

Given format 1 is used many times it would be neater if the null character termination was in the format rather than the write. I just spend a few minutes scratching my head and googleing.... Any ideas?

0 Kudos
44 Replies
andrew_4619
Honored Contributor II
1,582 Views

Answering my own question.....     

        1 format(f10.3,'\0')

Seems to do the trick......

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,582 Views

app4619 wrote:

Answering my own question.....     

        1 format(f10.3,'\0')

Seems to do the trick......

I think the above may be a bug. However

1 format(f10.3, '\0'C)

would be correct.

as well as

1 format(f10.3, ''C)

(two ' characters)

Jim Dempsey

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

A good spot Jim but we are both wrong the '\0'  literally a \ and a 0 whilst if you make it a C string with the \0'C the complier throws its teddy out of the pram - error #6186: This character is not valid in a format list.  

Any more ideas anyone????

 

 

0 Kudos
mecej4
Honored Contributor III
1,582 Views

You left us in the dark as to what the purpose of the null is, but here is my attempt:

character(7) :: fmt = '(f10.3)'
character(20) :: gbuf
real :: flt = 3.142
integer :: i
gbuf(11:11)=char(0)
write(gbuf(1:10),fmt)flt
write(*,'(20(1x,Z2))')(gbuf(i:i),i=1,len(gbuf))
end

 

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

What I was doing was putting numeric data into strings to throw at Windows sdk routines for dialog boxes. Generally these must be null terminated as the sdk is setup for C++. I was looking for a neater way rather than writing a char(0) or concatenating to the string  gchar(1:n)//char(0). My earlier post is wrong - see below

1 format(f10.3,'\0'C)
write(gchar,1) flt ! works
write(gchar,"(f10.3,'\0'C)") flt  !fails-error #6186: This character is not valid in a format list.

 

0 Kudos
mecej4
Honored Contributor III
1,582 Views

As you may have noted, I placed the null into gbuf(11:11) and exposed only the substring gbuf(:10) to the Fortran I/O runtime; this was intended to keep the null out of reach of any format string checking code in the runtime.

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

Yes I noted that, for my purposes the 1 format.... style works fine and suits my purposes for being short and clear. 

thanks

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,582 Views

app4619 wrote:

A good spot Jim but we are both wrong the '\0'  literally a \ and a 0 whilst if you make it a C string with the \0'C the complier throws its teddy out of the pram - error #6186: This character is not valid in a format list.  

Any more ideas anyone????

program NULL
  implicit none
  character(10) :: funk
  funk='abc\0def'
  print *,funk
  funk='abc\0def'C
  print *,funk
end program NULL

 abc\0def
 abc def

 

I see no teddy

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,582 Views

Curious:

program NULL
    implicit none
    character(10) :: funk
    funk='abc\0def'
    print *,funk
    funk='abc\0def'C
    print *,funk
    print 1,'abc', 'def'
1   format(a3,'\0',a3)
    print 2,'abc', 'def'
2   format(a3,'\0'C,a3)
end program NULL

 abc\0def
 abc def
abc\0def
abcdef

Space between in 2nd line, not in 4th line

Jim Dempsey

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

jimdempseyatthecove wrote:

I see no teddy

Jim Dempsey

My post was misleading I corrected myself at #6

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views
    program Console3
    implicit none
    integer           :: ival, l1
    character(len=8)  :: gbuf1, gbuf2
    1 format(i4,'\0'C)    
    2 format(i4,A)    
    do l1=1,len(gbuf1) ! fill strings with something
        gbuf1(l1:l1)='@'
        gbuf2(l1:l1)='@'
    enddo
    ival=1234
    write(gbuf1,1) ival
    write(gbuf2,2) ival,char(0)
    !now check the results
    open(1,file='test.txt',status='unknown')
    write(1,*) iachar('@')
    do l1=1,len(gbuf1)
      write(1,*) l1,iachar(gbuf1(l1:l1)),iachar(gbuf2(l1:l1)) 
    enddo
    !      64
    !       1          49          49
    !       2          50          50
    !       3          51          51
    !       4          52          52
    !       5          32           0 space char, null char
    !       6          32          32
    !       7          32          32
    !       8          32          32
    end program Console3

So the Gbuf2 version works and the Gbuf1 version fails. Is there a valid/working option for format 1? To me it is better to have the null char in the format rather then remembering at add a char(0) to the end of every buffer write in this instance.

0 Kudos
IanH
Honored Contributor II
1,582 Views

Do you have to use a format statement?  Format specifications in character strings are much better, in that they can be built using constant expressions (that ultimately result in something of character type) and can be given a name that is a bit more descriptive.

Unfortunately, I think the compiler is being a bit overly critical of character edit descriptors that have NULL's in them (I think this is a compiler bug - because it is useful to do this occasionally - your use case for example.  But you can work around that.

PROGRAM FormatSpecWithNull
  IMPLICIT NONE
  ! You should be able to do this, but the compiler (erroneously, IMHO) 
  ! incorrectly complains.  Note the ACHAR putting a NULL in the 
  ! character string edit desscriptor.
  CHARACTER(*), PARAMETER :: fmt_spec_ = "(F10.3,'" // ACHAR(0) // "')"
  
  ! So we'll obsfuscate the format spec such that the compiler can't see 
  ! what we are doing at compile time.
  CHARACTER(:), ALLOCATABLE :: fmt_spec
  
  ! For testing.
  CHARACTER(11) :: string
  
  !*****************************************************************************
  
  fmt_spec = fmt_spec_
  
  ! Just for checking - note the NULL won't show properly.
  PRINT "('The format spec is ""',A,'""')", fmt_spec
  
  ! Define string so that we can see what it changes to.
  string = REPEAT('x', LEN(string))
  WRITE (string, fmt_spec) 9.0        ! 6661
  
  ! Is there a NULL where we expect?
  PRINT "('The character at position 11 has IACHAR of ',I0)",  &
      IACHAR(string(11:11))
  
END PROGRAM FormatSpecWithNull

 

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

No I do not need to have a format statement, I did some examples using formats built into strings but they all failed. Your sample is quite interesting, I think the key in your example is the allocate, to cheat the compile time behaviour.

This seems like a sledge hammer to crack a nut though, I am not sure that the Intel compiler is being very  friendly in this instance.

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,582 Views

App4619,

Experimenting with your program a bit more yields

program NULL
  implicit none
  integer           :: ival, l1,ival2
  character(len=8)  :: gbuf1, gbuf2
1 format(i4,'A\0A'C,i1)    
2 format(i4,A)    
  do l1=1,len(gbuf1) ! fill strings with something
    gbuf1(l1:l1)='@'
    gbuf2(l1:l1)='@'
  enddo
  ival=1234
  ival2 = 5
  write(gbuf1,1) ival, ival2
  write(gbuf2,2) ival,char(0)
  !now check the results
  open(1,file='test.txt',status='unknown')
  write(1,*) iachar('@')
  do l1=1,len(gbuf1)
    write(1,*) l1,iachar(gbuf1(l1:l1)),iachar(gbuf2(l1:l1)) 
  enddo
end program NULL
          64
           1          49          49
           2          50          50
           3          51          51
           4          52          52
           5          65           0
           6          53          32
           7          32          32
           8          32          32

Note, that not only is the null omitted (2nd character of embedded text), but also the 3rd character of the embedded text of the format is omitted. It would seem that the code writer of the affected piece of code is using the string as if it were a C string. I guess one could argue that "you said it was a C string", and took that to interpret the string is terminated by non-inclusive NULL. Changing 1 format to..., yields

...
1 format(i4,'A'\\''C\\'A',i1)    
...
          64
           1          49          49
           2          50          50
           3          51          51
           4          52          52
           5          65           0
           6          65          32
           7          53          32
           8          32          32

In the above, the NULL is stripped (but 2nd A is present).

It mat be time for someone familiar with the standards with respect to the edit descriptors containing unusual characters, such as NULL, TAB, Escape Sequences, other...

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
1,582 Views

I don't recommend trying to force a NUL into a format string. Find another solution.

0 Kudos
Anthony_Richards
New Contributor I
1,582 Views

I'm not sure if somewhere above is the suggestion to initialize your
format with CHAR(0), but that would appear to work only if you specify the
exact number of characters to write to, or else the unwritten-to storage
bytes finish up filled with codes for blank characters. It would appear much
simpler to bite the bullet and just concatenate the CHAR(0) when needed.

	CHARACTER(256) MYSTRING
        REAL*8 NUMBER
	INTEGER(4) I

	DO I=1,256
	MYSTRING(I:I)=CHAR(0)
	END DO

	NUMBER=1234.567D+89
	WRITE(MYSTRING(1:12),'(D12.3)') NUMBER

	PAUSE  ! at this point, MYSTRING still has CHAR(0) in all places except the first 12

	DO I=1,256
	MYSTRING(I:I)=CHAR(0)
	END DO

	NUMBER=1234.567D+89
	WRITE(MYSTRING,'(D12.3)') NUMBER

        PAUSE ! At this point, MYSTRING has code for blank (02) in all places after the first 12

 

 

 

0 Kudos
andrew_4619
Honored Contributor II
1,582 Views

@Anthony:

You are correct! The 2 methods I already use are //char(0) or to write char(0) to an A format as the last i/o item for an internal write. It just happens I am converting some window dialogs from IFLOGM to using the Windows sdk direct and there were many strings created with formatted writes of real data. Adding a terminator NUL to the format would seem a logical step i.e. the change in one place rather than many. The reality is that adding a NUL within a format is not practical and indeed the Ifort compiler does not seem to work in a consistent way IMO.

@Steve "I don't recommend trying to force a NUL into a format string. Find another solution."

Based on the results above it is clearly foolish to try!!! Other solutions do exist, however, looking at the range of examples from a number of contributors, is the compiler behaving correctly and/or in a useful manner in this respect?

 

 

0 Kudos
Steven_L_Intel1
Employee
1,582 Views

Well, it should not be allowing a format item that looks like a C string. I'll file a bug report about that.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,582 Views

I'd suggest creating a generic function call to the sdk library functions. One taking CHARACTER*(*) arguments, and the other taking C_PTR arguments. The C_PTR one need only have the attribute declarations to match the signature of the sdk library function.

The CHARACTER*(*) functions can make a copy, LENTRIM and append the null, then"call" the library function using the LOC of the temporary copy(s) of the arg(s).

Jim Dempsey

0 Kudos
IanH
Honored Contributor II
1,437 Views

Steve Lionel (Intel) wrote:

I don't recommend trying to force a NUL into a format string. Find another solution.

 

:(

0 Kudos
Reply