printf issue in linux - linux

Following is a simple program to print formatted "1.2" on HP & Linux.
However, the behavior is different.
I do not want to make the question bigger but the program where this is actually occurring has a float value in a string, so using %f is not an option (even using sprintf).
Has anyone encountered this before? Which behavior is correct?
This should not be a compiler issue but still have tried it on gcc, icpc, icc, g++.
#include <stdio.h>
int main()
{
printf("%s = [%010s]\n", "[%010s]", "1.2");
return 0;
}
**HP:**
cc test2.c -o t ; ./t
[%010s] = [00000001.2]
**Linux:**
icc test2.c -o t ; ./t
[%010s] = [ 1.2]
Edit: Thank you all very much for the responses :)

From the glibc printf(3) man page:
0 The value should be zero padded. For d, i, o, u, x, X, a, A, e,
E, f, F, g, and G conversions, the converted value is padded on
the left with zeros rather than blanks. If the 0 and - flags
both appear, the 0 flag is ignored. If a precision is given
with a numeric conversion (d, i, o, u, x, and X), the 0 flag is
ignored. For other conversions, the behavior is undefined.
So a 0 flag with s cannot be expected to pad the string with 0s on glibc-based systems.

According to the man page, the behaviour of the 0 flag for anything other than d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions is undefined. So both are fine.
EDIT: When I say "fine", I mean from the compiler/libc standpoint. From your application's point of view, the behaviour you're relying on (on both Linux & HP) is a bug and you should do your formatted printing correctly.

If you don't want leading zero fill, omit the leading zero fill indicator:
printf("%s = [%10s]\n", "[%010s]", "1.2");
It is somewhat surprising that an implementation honors filling a string with zeros, but it is easily corrected.

Adding to what Ignacio Vazquez-Abrams said, according to the documentation for printf, the result of what you are doing is undefined behavior. The fact that two OSes produce different results is not unexpected.
In fact, compiling your code with gcc 4.5.2 on Ubuntu gives the following warning:
warning: '0' flag used with ā€˜%sā€™ gnu_printf format

Related

IO Fortran format command issue [duplicate]

I would like to have a Fortran write statement formatted to depend on some variable. For example, I could write:
write(*,'(3f15.3,3f9.2)') x,y,z,(var(i),i=1,nvari)
where nvari = 3. But, what if, in some cases, I actually have 4 variables (i.e. nvari = 4). I would like to write something like this:
write(*,'(3f15.3,nvari(f9.2))') x,y,z,(var(i),i=1,nvari)
Now, nvari can be anything and the output will work as I like. How can I make something like this work?
If you are using Intel fortran, it has a proprietary extension for this -- you can include an existing variable in angle brackets to act as a specifier:
write(*,'(3f15.3,<nvari>f9.2)') x,y,z,(var(i),i=1,nvari)
If you compiler supports it, '(3f15.3, *(f9.2))'
If you have an older compiler, just use a larger number than you will have items to output, e.g., '(3f15.3, 999(f9.2))'. You don't have to use up the format.
For the most complicated cases you can write a format to a string and use that as your format:
write (string, '( "(3f15.3, ", I4, "(f9.2))" )' ) nvari
write (*, string ) x,y,z, (array(i), i=1,nvari)
With the understanding of formats, including format reversion, the use of string formats is rarely necessary.
Instead of writing the format directly in the write statement, it's also possible to use a character variable.
character(len=32) :: my_fmt
my_fmt = '(3f15.3,3f9.2)'
write(*, my_fmt) x, y, z, (var(i), i = 1, nvari)
Now it is possible to manipulate the character variable to contain the wanted repeat count before the write statement, using a so-called internal write, or write to internal file.
write(my_fmt, '(a, i0, a)') '(3f15.3,', nvari, 'f9.2)'
(Just make sure the declared length of my_fmt is long enough to contain the entire character string.)
You wanted to write something like this:
write(*,'(3f15.3,nvari(f9.2))') x, y, z, (var(i), i=1,nvari)
In fact, there is an old trick in the Fortran standard that allows you to omit the nvari, thus:
write(*,'(3f15.3,(f9.2))') x, y, z, (var(i), i=1,nvari)
or even thus:
write(*,'(3f15.3,f9.2)') x, y, z, (var(i), i=1,nvari)
The standard says that the last descriptor in the format is implicitly repeated as often as is necessary to accommodate all of the variables in the list. That 'last descriptor' could be parenthesized such that the last group of descriptors is implicitly repeated, for example:
write(*,'(3f15.3,(2x,f9.2))') x, y, z, (var(i), i=1,nvari)

Static types and conversions

Suppose I have an algol-like language, with static types and the following piece of code:
a := b + c * d;
where a is a float, b an integer, c a double and d a long. Then, the language will convert d to long to operate with c, and b to double to operate with c*d result. So, after that, the double result of b+c*d will be converted to float to assign the result to a. But, when it happens?, I mean, do all the conversions happens in runtime or compile time?
And if I have:
int x; //READ FROM USER KEYBOARD.
if (x > 5) {
a:= b + c * d;
}
else {
a := b + c;
}
The above code has conditionals. If the compiler converts this at compile time, some portion may never run. Is this correct?
You cannot do a conversion at compile-time any more than you can do an addition at compile time (unless the compiler can determine the value of the variable, perhaps because it is actually constant).
The compiler can (and does) emit a program with instructions which add and multiply the value of variables. It also emits instructions which convert the type of a stored value into a different type prior to computation, if that is necessary.
Languages which do not have variable types fixed at compile-time do have to perform checks at runtime and conditionally convert values to different types. But I don't believe that is the case with any of the languages included in the general category of "Algol-like".

Lua format.string can't format float as decimal (%d) as of 5.3

I recently upgraded from Lua 5.2.3 to 5.3.1 but I noticed all my scripts that perform a string.format started failing if it tried to format a float using %d
local anExampleString = string.format("Sample Number: %d",10.100000001) -- Fails on 5.3.1, works on 5.2.3
local aWorkingString = string.format("Sample Number: %.0f",10.100000001) -- Works on 5.3.1
Is this by design? I can't seem to find the change documented anywhere.
In Lua 5.3, the number type has two subtypes, integer and float.
From string.format
Options A, a, E, e, f, G, and g all expect a number as argument. Options c, d, i, o, u, X, and x expect an integer.

Reading Unformatted Binary file: Unexpected output - Fortran90

Preface: I needed to figure out the structure of a binary grid_data_file. From the Fortran routines I figured that the first record consists of 57 bytes and has information in the following order.
No. of the file :: integer*4
File name :: char*16
file status :: char*3 (i.e. new, old, tmp)
.... so forth (rest is clear from write statement in the program)
Now for the testing I wrote a simple program as follows: (I haven't included all the parameters)
Program testIO
implicit none
integer :: x, nclat, nclon
character :: y, z
real :: lat_gap, lon_gap, north_lat, west_lat
integer :: gridtype
open(11, file='filename', access='direct', form='unformatted', recl='200')
read(11, rec=1) x,y,z,lat_gap,lon_gap, north_lat,west_lat, nclat, nclon, gridtyp
write(*,*) x,y,z,lat_gap,lon_gap, north_lat,west_lat, nclat, nclon, gridtyp
close(11)
END
To my surprise, when I change the declaration part to
integer*4 :: x, nclat, nclon
character*16 :: y
character*3 :: z
real*4 :: lat_gap, lon_gap, north_lat, west_lat
integer*2 :: gridtype
It gives me SOME correct information, albeit not all! I can't understand this. It would help me to improve my Fortran knowledge if someone explains this phenomenon.
Moreover, I can't use ACCESS=stream due to machine being old and not supported, so I conclude that above is the only possibility to figure out the file structure.
From your replies and what others have commented, I think your problem might be a misunderstanding of what a Fortran "record" is:
You say that you have a binary file where each entry (you said record, but more on that later) is 57 bytes.
The problem is that a "record" in Fortran I/O is not what you would expect it is coming from a C (or anywhere else, really) background. See the following document from Intel, which gives a good explanation of the different access modes:
https://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/2011Update/fortran/lin/bldaps_for/common/bldaps_rectypes.htm
In short, it has extra data (a header) describing the data in each entry.
Moreover, I can't use ACCESS=stream due to machine being old and not supported, so I conclude that above is the only possibility to figure out the file structure. Any guidance would be a big help!
If you can't use stream, AFAIK there is really no simple and painless way to read binary files with no record information.
A possible solution which requires a C compiler is to do IO in a C function that you call from Fortran, "minimal" example:
main.f90:
program main
integer, parameter :: dp = selected_real_kind(15)
character(len=*), parameter :: filename = 'test.bin'
real(dp) :: val
call read_bin(filename, val)
print*, 'Read: ', val
end program
read.c:
#include <string.h>
#include <stdio.h>
void read_bin_(const char *fname, double *ret, unsigned int len)
{
char buf[256];
printf("len = %d\n", len);
strncpy(buf, fname, len);
buf[len] = '\0'; // fortran strings are not 0-terminated
FILE* fh = fopen(buf, "rb");
fread(ret, sizeof(double), 1, fh);
fclose(fh);
}
Note that there is an extra parameter needed in the end and some string manipulation because of the way Fortran handles strings, which differs from C.
write.c:
#include <stdio.h>
int main() {
double d = 1.234;
FILE* fh = fopen("test.bin", "wb");
fwrite(&d, sizeof(double), 1, fh);
fclose(fh);
}
Compilation instructions:
gcc -o write write.c
gcc -c -g read.c
gfortran -g -o readbin main.f90 read.o
Create binary file with ./write, then see how the Fortran code can read it back with ./readbin.
This can be extended for different data types to basically emulate access=stream. In the end, if you can recompile the original Fortran code to output the data file differently, this will be the easiest solution, as this one is pretty much a crude hack.
Lastly, a tip for getting into unknown data formats: The tool od is your friend, check its manpage. It can directly convert binary represantations into a variety of different native datatypes. Try with the above example (the z adds the character representation in the right-hand column, not very useful here, in general yes):
od -t fDz test.bin

Writing array of Struct to a binary file

I am not understanding whats erroneous in the program. I am defining a pointer to an array of structures. Malloc'ed enough memory for it. Initialized the array elements. Then used fwrite to write the array on to a binary file. Then attempting to read the same, back into another pointer to a similar array, which has enough memory malloc'ed to it.
#include<stdio.h>
typedef struct ss{
int *p;
char c;
double d;
char g;
float f;
} dd;
main(){
dd (*tt)[5];
int i=0,a[5]={4,1,6,9,3};
tt=malloc(sizeof(struct ss[5]));
for(i=0;i<5;i++){
tt[i]->p=malloc(sizeof(int));
tt[i]->p=&a[i];
tt[i]->c=(char)('a'+i);
tt[i]->d=(double)(5.234234+i);
tt[i]->g=(char)('A'+i);
tt[i]->f=(float)(15.234234+i);
}
FILE *F;
F=fopen("myfile","w+b");
size_t l;
l=fwrite(tt,sizeof(*tt),1,F);
fseek(F,0,SEEK_SET);
//printf("sizeof(dd)=%d sizeof(*tt) =%d bytes written %d\n",sizeof(dd),sizeof(*tt),l);
dd (*xx)[5];
xx=malloc(sizeof(struct ss[5]));
l=fread(xx,sizeof(*xx),1,F);
for(i=0;i<5;i++){
printf("%d, %c,%f,%c,%f\n",*(xx[i]->p),xx[i]->c,xx[i]->d,xx[i]->g,xx[i]->f);
}
printf("Date Read %d \n",l);
for(i=0;i<5;i++){
free(xx[i]->p);
}
free(xx);
free(tt);
fclose(F);
remove("myfile");
}
Output:
4,a,5.234234,A,15.234234
Segmentation fault
You weren't writing your data where you thought you were, because you were accessing tt incorrectly. Your incorrect access was consistent, and therefore you could read out the first record, but the second record was nowhere near where you thought it was- it was, in fact, being written into uninitialized memory and never saved. Trying to access the reloaded data shows this. Additionally, your int* in your struct couldn't be written out correctly the way you wrote it out, but this is moot because of how your program is structured- it would be wrong if you were trying to load the file in a separate run of the program. fwrite and fread cannot follow your int*, because it's only looking at your struct as a bit pattern- it is faithfully reconstructing your pointer, but now you have a pointer to a random chunk of memory that you didn't actually do anything with! In this case, though, your pointers remain valid because you never overwrote the data, but this is specific to the scenario of writing the file out, not flushing the memory, and reading it back in without the program being closed- which is not a realistic scenario for file-writing. There's another StackOverflow question that explains this bug in more detail.
Anyway, here's the much bigger problem with how you're accessing memory, with other lines removed:
dd (*tt)[5];
//...
tt=malloc(sizeof(struct ss[5]));
for(i=0;i<5;i++){
tt[i]->p=malloc(sizeof(int));
tt[i]->p=&a[i];
//...
}
C declarations are read with The Clockwise Spiral Rule, so let's look at what we've said about tt and compare it to how we're using it.
tt is the variable name. To its right is a closing parenthesis, so we keep processing the current scope. We encounter a *, and then the matching paren, then a static array size, then a type. Using The Clockwise Spiral Rule, tt is a pointer to an array (size 5) of dd. This means that if you dereference tt (using (*tt)), you get a dd[5], or, if you prefer to think of it that way (C certainly does), a pointer to the beginning of a block of memory large enough to hold your structure. More importantly, that's what you've said it is. C isn't actually very picky about is pointer types, and that's why your code compiles even though you're committing a serious type error.
Your malloc statement is correct: it is initializing tt with a memory location that the operating system promised has enough space for your five ss. Because C doesn't bother with silly things like array size bounds checking, a 5-element array of struct ss is guaranteed to be exactly five times the size of a single struct ss, so you could actually have written malloc(5 * sizeof(dd)), but either way of writing it is fine.
But let's look at what happens here:
tt[i]->p=malloc(sizeof(int));
Uh-oh. tt is a pointer to an array of struct dd, but you've just treated it as an array of pointers to struct dd.
What you wanted:
Dereference tt
Find the ith element in an array of pointers to dd
Go to field p
Assign it a pointer to space for an int
What you actually got:
Find the ith element in an array of pointers to arrays of dd
Dereference it, treating it as a pointer to dd, since C doesn't know the difference between arrays and pointers
Go indirectly to field p
Assign it a pointer to space for an int
When i is 0, this works properly, because the zeroth element in an array and the array itself are in the same location. (An array has no header, and C _does not understand the difference between arrays and pointers and allows you to use them interchangeably, which is why this compiles at all.)
When i is not 0, you make an enormous mess of memory. Now you are writing to whatever memory happened to follow your pointer! It's actually a pointer, but you told C it was an array, and it believed you, added 1 element-width to its location, and tried to do all those operations. You're using arrays exactly where you should be using pointers, and pointers exactly where you should be using arrays.
You only write to the memory you allocated for element 0. Beyond that, you're writing into unrelated memory, and it's luck (bad luck, in your case) that kept your program from crashing right there. (If it had, you'd have had an easier time finding this as the guilty line.) When you fwrite your allocated memory, the first element is valid, the rest is garbage, and your fread results in a data structure that has one valid element, then random heap garbage that resulted in a crash when you tried to dereference a pointer (that would only be valid because the program didn't end).
Here's the right way to access your pointer-to-array:
(*tt)[i].p=malloc(sizeof(int));...
Also, you're allocating memory, then immediately forgetting your only reference to it, which is a memory leak, since you're overwriting the pointer with a reference to the static array you're initializing everything with. Use this instead:
*((*tt)[i].p)=a[i]
I strongly encourage you to study A Tutorial on Pointers and Arrays in its entirety. It will help you avoid this class of issue in the future.
Be aware that you are reading xx incorrectly when printing its contents in exactly the same manner.
You're pointer usage is incorrect. In this code snippet:
dd (*xx)[5];
xx=malloc(sizeof(struct ss[5]));
l=fread(xx,sizeof(*xx),1,F);
for(i=0;i<5;i++){
printf("%d, %c,%f,%c,%f\n",*(xx[i]->p),xx[i]->c,xx[i]->d,xx[i]->g,xx[i]->f);
}
You are declaring xx as a pointer to an array of 5 'dd' structures. This is where it gets weird. It's a pointer to five structures and not an array of five structures.
It would look something like this in memory:
dd[0] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}]
dd[1] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}]
...
dd[4] = [{p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}, {p, c, d, g, f}]
Instead of the intended:
dd[0] = {p, c, d, g, f}
dd[1] = {p, c, d, g, f}
...
dd[4] = {p, c, d, g, f}
As you are iterating from 0 to 5, each array access is advancing your array sizeof(ss[5]) bytes in memory instead of sizeof(ss) bytes. Take out the extra pointer.
dd* xx;
xx = (dd*)malloc(sizeof(dd) * 5);
l = fread(xx, sizeof(dd), 5, F);
for(i = 0; i < 5; ++i) {
printf("%d, %c, %f, %c, %f\n", xx[i].p, , xx[i].c, xx[i].d, xx[i].g, xx[i].f);
}
Additionally you have a problem with your structure. If it is meant to be directly written to disk like this, it cannot contain pointers. Thus your 'int *p;' member needs to instead be 'int p;'. Otherwise if you read this file from a separate application, the pointer you stored will not point at the integer anymore, but at unallocated memory.
Writing application:
int *p = 0x12345 ---> 5
0x12345 gets stored in the file for p.
Writing application reads the file.
int *p = 0x12345 ---> 5
The pointer still points at the same memory because it is still the same memory
layout.
New application reads the file.
int *p = 0x12345 ---> ?????
The pointer doesn't point to a known piece of memory because the memory layout
has changed in this new instance of the application. This could crash or
cause a security issue.

Resources