Function call problems (64-bit)

M

Max

Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)
x = 0.;

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;
double *x = malloc(n * sizeof(doublereal));
int retval;

retval = fun1((integer &)n, x);

return 0;
}


I get segmentation fault on 64-bit architecture. The problem is that n
is not passed correctely to fun1, even with a cast. Defining in main()

integer n = 5

then it works. A more elegant solution?

Thanks
Max
 
?

=?ISO-8859-1?Q?Bj=F8rn_Augestad?=

Max said:
Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)
x = 0.;

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;


integer n = 5;
double *x = malloc(n * sizeof(doublereal));

doublereal* x = malloc(n * sizeof *x);
int retval;

retval = fun1((integer &)n, x); retval = fun1(&n, x);

return 0;
}


I get segmentation fault on 64-bit architecture. The problem is that n
is not passed correctely to fun1, even with a cast. Defining in main()

integer n = 5

then it works. A more elegant solution?

Use the defined data types(integer, doublereal). Your problem is
probably that sizeof(int) != sizeof(long int).

HTH
Bjørn
 
R

Richard Heathfield

Max said:
Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)
x = 0.;

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;
double *x = malloc(n * sizeof(doublereal));
int retval;

retval = fun1((integer &)n, x);

return 0;
}


I get segmentation fault on 64-bit architecture.


If you got the above code to compile without diagnostics, you're not using a
C compiler. A diagnostic is required for the line:

retval = fun1((integer &)n, x);
 
M

Mike Wahler

Max said:
Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)

Beware! If the address of a negative value is passed for 'n',
this loop will cause 'i' to overflow, giving undefined behavior.

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;
double *x = malloc(n * sizeof(doublereal));

What if the allocation fails?
int retval;

retval = fun1((integer &)n, x);

This is a syntax error. Presumably you meant:
retval = fun1(&n, x);

free(x);
return 0;
}


I get segmentation fault on 64-bit architecture. The problem is that n
is not passed correctely to fun1,

Yes, that's the problem. The problem that needs to be fixed.
even with a cast.

Many people suffer from the misconception that a cast will
somehow magically let one safely violate the rules. All it
typically does is stop a compiler from warning you that your
gun is pointing at your foot and the safety is off.
Defining in main()

integer n = 5

then it works.

I works when doing that because then you're following the rules.
A more elegant solution?

One of our comp.lang.c denizens once remarked: (paraphrased)
"Lie to your compiler, and it will get its revenge".
He's right.

Elegant solution: Forget 'elegant', concentrate on 'solution'.
Solution: Don't Lie.

It appears that for your implementation, the sizes and/or
representations of types 'int' and 'long int' are not the
same. When you pass the address of (main()'s) 'n', 'fun1()',
when dereferencing understandably gets it wrong, probably
trying to access memory not part of the object 'n' in 'main()'.
(But officially, the behavior is simply 'undefined' meaning
that anything might happen).

The cleanest solution is to stop passing a pointer and pass
'n' by value directly (the language already defines a built
in conversion from type 'int' to 'long int'.

int fun1(long int n, double *x)
{
/* etc */
}

int main()
{
int n = 5;
double *x = malloc(n * sizeof *x);
if(x)
{
fun1(n, x);
free(x);
}
return 0;
}

Why that 'f2c' converter needs to use those typedefs I don't
know. IMO they're just obfuscating clutter. C already has perfectly
good type names. Also I'm suspicious of any code 'converted'
by automation. Often the languages involved have sufficient
differences in semantics that the target language is not exploited
effectively, often leading to buggy and/or poor performing,
at best unreadable, code.

-Mike
 
M

Max

Sorry, I have just generated this example for posting The correct line
is

retval = fun1((integer *)&n, x);

and no warnings nor errors should arise with gcc-3.4 -Wall.
 
M

Max

Thanks for the good tips (especially for the remark). Anyway, such
f2c-translated routines are not under my control, therefore I have to
use them as they are. As you have said, the conversion between "int"
and "long int" is included in the language specification, therefore
this should be the solution

int n = 5;
integer n1 = n;

retval = fun1(n1, x);

For the other remarks: this program is just an example, malloc is
checked and argument are always positive...
Anyway, thanks for your help
 
M

Mike Wahler

Max said:
Sorry, I have just generated this example for posting The correct line
is

retval = fun1((integer *)&n, x);

and no warnings nor errors should arise with gcc-3.4 -Wall.

Absence of compiler errors does not at all
guarantee correct run time behavior.

The above *might* work, but it's equally possible
(I think probable) that it will not. There's no
guarantee from the language that it will.

-Mike
 
P

pete

Max said:
Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)
x = 0.;

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


I dislike reading code like that.
Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;
double *x = malloc(n * sizeof(doublereal));
int retval;

retval = fun1((integer &)n, x);

return 0;
}

I get segmentation fault on 64-bit architecture. The problem is that n
is not passed correctely to fun1, even with a cast. Defining in main()

integer n = 5

then it works. A more elegant solution?

There's nothing elegant about int n, it's wrong.

You have
m = (*n);
where the type of (*n) is a long.

There's no long object defined anywhere
for the (*n) expression to refer to.
You're casting an int address to a long address
and dereferencing it. That's undefined.
 
M

Max

I am sorry, instead of "preview" I clicked on "send" and I could not
check the correctness.
This works:

retval = fun1(&n1, x);

Max
 
B

Barry Schwarz

Warning: newbie question!
If I have a function (translated from fortran using f2c)

int fun1(integer *n, doublereal *x)
{
integer m, i;

m = (*n);
for(i = 0; i < m; i++)
x = 0.;

return 0;
}

where (from f2c.h)

typedef long int integer;
typedef double doublereal;


Then I use it in a C program written from scratch:

< all include files here>

int main()
{
int n = 5;
double *x = malloc(n * sizeof(doublereal));
int retval;

retval = fun1((integer &)n, x);


You cannot lie to the compiler and expect things to work. fun1
expects to receive a long*. You are giving it something that looks
like a long* but actually points to an int.

If this int is not aligned properly for a long you have invoked
undefined behavior. If your machine requires alignment, then a seg
fault is a desirable result.

If sizeof(int) != sizeof(long), the attempt to dereference the
address also invokes undefined behavior. As a practical matter, it
will probably result in a value wildly different than 5L. This would
most likely cause the array index to go way out of bounds and again a
seg fault is a desirable result.
return 0;
}


I get segmentation fault on 64-bit architecture. The problem is that n
is not passed correctely to fun1, even with a cast. Defining in main()

integer n = 5

then it works. A more elegant solution?

How much more elegant can a solution be? This is cheap (almost free),
simple, effective, portable, efficient, correct, etc. Maybe you are
looking for something like "rewrite the f2c program so it produces
decent code"?


<<Remove the del for email>>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,173
Messages
2,570,938
Members
47,475
Latest member
NovellaSce

Latest Threads

Top