why it doesn't work?

J

junky_fellow

Guys,

Consider the following two files, files test.c and test1.c

Contents of test1.c are as follows:
---------------------------------------------------

int arr[] = { 0x100, 0x200 };
int main(void)
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
func();
}

Contents of test1.c
------------------------------
extern int *arr;

func()
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
}

The 2 files are compiled without any error, but when I run the
executable generated, it crashes with segmentation fault.

Can someone please explain what is the reason for crash ?
 
M

Michael Tsang

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

---------------------------------------------------

int arr[] = { 0x100, 0x200 };
int main(void)
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
func();
}

Contents of test1.c
------------------------------
extern int *arr;

func()
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
}
Short:
A pointer object is not an array object, they aren't layout-compatible.

Long:
The type of arr in both TU aren't the same. The above arr is of int[2], the
below is of int* . In terms of implementation, let sizeof(int)==4 and
sizeof(int*)==8, and *array* *object* arr in the above TU is stored at
0x12345678. When the TUs are linked together, func() thinks that a *pointer*
*object* is stored at 0x12345678, so, the func() runs, it reads 8 bytes from
0x12345678, that is, assuming little-endian machine, 0x0000020000000100 and
try to dereference that address, of cause, the program crashes.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkt5YbsACgkQm4klUUKw07BrtwCfUOKZXPA932cL4jgqCP+g+Q6q
UrwAmgIGxnubcQ7K1O21PsmBQX3jt425
=tin7
-----END PGP SIGNATURE-----
 
B

Ben Bacarisse


....and gals.
Consider the following two files, files test.c and test1.c

Contents of test1.c are as follows:
---------------------------------------------------

int arr[] = { 0x100, 0x200 };
int main(void)
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
func();
}

Contents of test1.c

In addition to the comments you've already had, if you don't want to
commit yourself to the size, you can declare arr like this:

extern int arr[];
func()
{
printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
}

If this is C90 you need a return statement in main. If this is C99
you can't have a function with return type declared using implicit
int. Furthermore, both files need #include <stdio.h> and the format
specifier should match the type of the arguments you are printing (x
is for unsigned int).

Some of these are all details, but what do you gain by playing fast a
loose with the compiler? One day, one of these will bite you (but
probably never the last).
The 2 files are compiled without any error, but when I run the
executable generated, it crashes with segmentation fault.

You need to turn up the warning level and then some of the matters
I've raised will be warned about. I prefer to be told!

<snip>
 
J

junky_fellow

   Consider the following two files, files test.c and test1.c
Contents of test1.c are as follows:
---------------------------------------------------
int arr[] = { 0x100,  0x200 };
int main(void)
{
   printf("arr[0]=%x arr[1]=%x\n", arr[0], arr[1]);
   func();
}
Contents of test1.c

Change this to:

extern int arr[2];

and all will be well.

arr is an array, not a pointer. The difference is important.

<snip>

I understand the difference between the types of "arr" in two files.
What I wanted to know is what the linker did when it encountered
"extern int *arr"?
First of all why it didn't give any error ?
What value it assigned to "arr declared as integer pointer" ?
When I print the value of "arr" (printf("arr=%p", arr)) in test1.c,
value printed was 0x100.

Can you please tell, why the (int *arr) was assigned value 0x100?
 
S

Seebs

I understand the difference between the types of "arr" in two files.
What I wanted to know is what the linker did when it encountered
"extern int *arr"?

Whatever it wanted?
First of all why it didn't give any error ?

Why should it have?
What value it assigned to "arr declared as integer pointer" ?
When I print the value of "arr" (printf("arr=%p", arr)) in test1.c,
value printed was 0x100.
Can you please tell, why the (int *arr) was assigned value 0x100?

It wasn't.

Okay, here's the thing. You declared an int[] containing two values, so
that looks like, in memory:
0x100 0x200
you then told something that, at that location, it would find a pointer.
So the pointer was "0x100".

This behavior depends on a lot of things, including the coincidence that
pointers and ints are the same size, and not all linkers would have done
it, but that's probably what happened.

-s
 
P

Peter Nilsson

Seebs said:
Whatever it wanted?


Why should it have?

Why shouldn't it have? It's a fair question! If they were in
the same translation unit, the implementation would be required
to issue a diagnostic.

Of course, the answer is that, for historical reasons (which
still exist today,) C implementations tend to operate in
3 stages (well 2 and a bit): pre-processing, compilation and
linking. Traditionally, type information was not passed to
linkers [hence name mangling in most C++ implementations.]

But these days, all sorts of debugging information is
available. So the question of why the standard doesn't
require a diagnostic in this case is a valid one IMO,
even if it should be asked in comp.std.c.
 
S

Seebs

But these days, all sorts of debugging information is
available. So the question of why the standard doesn't
require a diagnostic in this case is a valid one IMO,
even if it should be asked in comp.std.c.

I think it's actually plenty topical here. I doubt that requirement will
make it in "soon", because of the need for support for existing linkers. I'd
personally like to see it, though.

-s
 
G

gwowen

But these days, all sorts of debugging information is
available. So the question of why the standard doesn't
require a diagnostic in this case is a valid one IMO,
even if it should be asked in comp.std.c.

I would guess the answer is "because at the time the standard was
first written, such a clause would have required almost every linker
in the world to be rewritten at a fundamental level". Subsequent to
that the answer is "backwards compatibility".
 

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
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top