Bus error because of casting?

P

parjit

Hi,

when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));
strncpy(&longstr[10],(char *)pd,sizeof(double));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

strcpy(str,&(longstr[10]));
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

return(0);
}

Does anybody know why? Any ideas are wellcome. Thnx.
 
I

Ian Collins

Hi,

when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));
strncpy(&longstr[10],(char *)pd,sizeof(double));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

strcpy(str,&(longstr[10]));
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

How do you know longstr[10] is correctly aligned for a double?
 
S

Sjouke Burry

parjit said:
Hi,

when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));

pd does not point to a string, so you cannot stringcopy it.

d is a double, not a string.
strncpy(&longstr[10],(char *)pd,sizeof(double));

same error
fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

trying to print the adress of longstring as a double?????
strcpy(str,&(longstr[10]));
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));

trying to print the adress of str as a double?
fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

trying to print the adress of longstr??
return(0);
}

Does anybody know why? Any ideas are wellcome. Thnx.
Nowhere did you convert (write) d to a string.
No casting in any way will achieve that.
sprintf might do that for you.
Check that one out on your docs or with "man sprintf".
 
K

Keith Thompson

parjit said:
when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));
strncpy(&longstr[10],(char *)pd,sizeof(double));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

strcpy(str,&(longstr[10]));
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));

fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

return(0);
}

Does anybody know why? Any ideas are wellcome. Thnx.

I have to ask, is this deliberately bad code?

strncpy() almost certainly does not do what you think it does.
Read its documentation.

If the representation of d happens to contain a zero byte, strncpy()
will stop copying it. Would memcpy() suit your (rather mysterious)
purposes?

You copy the representation of d into longstr starting at position 0.
You then copy it again starting at position 10. Why do you do this?
What do you expect to happen if sizeof(double) > 10?

The bus error is probably caused by alignment issues. Neither
longstr[0] nor longstr[10] is guaranteed to be at an acceptable
alignment for type double. If double's alignment is greater than 2
bytes, then one of them is very nearly certain to be misaligned. The
behavior of accessing an object that isn't properly aligned for the type
you're using is undefined; a bus error is one of the friendliest
possibilities. (Other possibilities include quietly working but more
slowly, accessing memory from the nearest aligned address, and
corrupting your program's memory so that bad things happen later on.)

It's likely that longstr and str both happen to be properlyi aligned for
double, which explains the behavior you're seeing, but it's by no means
guaranteed.

What exactly are you trying to accomplish? If you show us code that
doesn't work, we can explain why it doesn't work, but we can't
help you write correct code if you don't tell us what your goal is.

If you want to print a double value stored in an array of char, it's
probably better to copy it from the array into a double object using
memcpy() (which doesn't care about the alignments of its arguments),
and then print the value of the double object.

Finally, some minor points:

"main()" should be "int main(void)".

"fprintf(stdout, args)" might as well be "printf(args)".

"return(0);" might as well be "return 0;"; return is not a function, and
it does not require parentheses.
 
J

Jens Thoms Toerring

parjit said:
when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).
#include<stdio.h>
#include<string.h>
main()

int main( void )
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;
strncpy(longstr,(char *)pd,sizeof(double));

strncpy() is unsuitable for anything else then copying strings.
One of the bytes of the double you try to copy might have all
bits set to 0, so it would look to strncpy() like the trailing
'\0' character of a string. If you really need to do that kind
of copying then use memcpy().
strncpy(&longstr[10],(char *)pd,sizeof(double));
fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

If this works then just because you were lucky. First of all
it requires that the double you copied didn't contain a byte
with all bits set to 0. And then the array of chars you copied
it to must be correctly aligned. Different architectures have
different alignment requirements, so even if this works on e.g.
an Intel processor it may fail with a bus error on another ar-
chitecture (where doubles e.g. can only start at memory addresses
that are integer multiples of 4 or 8 or some other number).
strcpy(str,&(longstr[10]));

If this works it's again just due to blind luck since it re-
quires that there's a '\0' char somewhere in 'longstr' which
induces strcpy() to stop copying.
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));
fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

Same problems here. With some luck it may work on one machine
but fail for a number of reasons on others. A bus error (due
to wrong alignment) is one of the possible failure modes.

Regards, Jens
 
K

Keith Thompson

Sjouke Burry said:
parjit said:
Hi,

when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));

pd does not point to a string, so you cannot stringcopy it.

d is a double, not a string.
strncpy(&longstr[10],(char *)pd,sizeof(double));

same error
fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

trying to print the adress of longstring as a double?????

No. He takes the address of the 0th character of longstr, converts
that address to double*, and then dereferences the resulting pointer.
The result is a value of type double, which is exactly what fprintf()
is expecting here.

The problem is that both the pointer conversion and the dereference
invoke undefined behavior -- not because the types are wrong, but
because the alignments may or may not be correct.
strcpy(str,&(longstr[10]));
fprintf(stdout," %15.15f\n",*(double *)&(str[0]));

trying to print the adress of str as a double?

Again, no; see above.
fprintf(stdout," %15.15f\n",*(double *)&(longstr[10]));

trying to print the adress of longstr??

Nope.

You *can* reliably store and extract double values in character arrays,
and sometimes there are even good reasons to do so. (We can only guess
whether the original poster actually has such a reason.) You just can't
reliably treat a slice of a character array *as if* it were a double
object, unless you do something to ensure its alignment. For example,
the following program works and exhibits well-defined behavior,
regardless of how the character array is aligned. (I use unsigned char
rather than char just because it tends to be a better way to represent
raw bytes.)

#include <stdio.h>
#include <string.h>

void print_double(unsigned char *buf)
{
double tmp;
memcpy(&tmp, buf, sizeof tmp);
printf("%15.15f\n", tmp);
}

int main(void)
{
double d = 3.14;
unsigned char buf[sizeof d];

memcpy(buf, &d, sizeof d);
print_double(buf);

return 0;
}
 
J

J. J. Farrell

Sjouke said:
parjit said:
when a run the following program the first and the second fprintf work
well but the third causes a bus error. (on a SUN Sparc Station 2, on a
VAX station there is no bus error).

#include<stdio.h>
#include<string.h>
main()
{
char longstr[1000];
char str[1000];
double d = 3.1415926535897932384626433832795028841971;
double *pd=&d;

strncpy(longstr,(char *)pd,sizeof(double));

pd does not point to a string,

How do you know? One of the bytes which d occupies might be zero in
which case '(char *)pd' does point to the first byte of a string. Not
that it's relevant really anyway.
so you cannot stringcopy it.

I don't know exactly what you mean by 'stringcopy', but he's using
strncpy() which isn't a string copy function - the only connection it
has with strings is that its behaviour changes when it sees a zero-value
byte in the source array. There's nothing wrong with this as C. We don't
know what the author intends this line to do, perhaps he wants it to do
exactly what it does. At a guess, he won't be expecting it to do what it
does when any but the last byte of d contains zero.

It's most likely that using memcpy() instead of strncpy() would always
do what's wanted, but that does depend on what's wanted.
d is a double, not a string.

True, but (char *)pd is a pointer to the first byte of an array of bytes
which may or may not be a string.
strncpy(&longstr[10],(char *)pd,sizeof(double));

same error

No error.
fprintf(stdout," %15.15f\n",*(double *)&(longstr[0]));

trying to print the adress of longstring as a double?????

No, trying to print a possibly misaligned double with possibly invalid
content as a double. That's the problem.
 
S

Shao Miller

parjit said:
Hi,

... ... ...
main()
{
... ... ...

Keith said:
... ... ...
Finally, some minor points:

"main()" should be "int main(void)".
... ... ...
int main( void )

Does the following code create a memory leak?

void main(){
... ... ...

Nick said:
The number of errors in your code reaches Schildt-like proportions.


main returns an int and an empty parameter list is indicated with
void. I hate your layout.

In thread "How can I access those memory areas which do NOT belong to me
... ... ...
main()
{
... ... ...

Shao said:
Your program includes a 'main' which is a little different from what C
Standards describe...
... ... ...
int main( void )

... ... ...

main()
{
... ... ...

Ian said:
Are you trolling?

... ... ...
 

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

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,114
Members
46,702
Latest member
VernitaGow

Latest Threads

Top