Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is wrong with this C program using extern keyword?

Tags:

c

I want to use variable a from foo.c in main.c, and I write:

foo.c
#include <stdio.h>

int a[] = {3, 2};

void foo()
{
    printf("foo\taddress of a:%x\n", a);
    printf("foo\tvalue of a[0]:%x\n", a[0]);
}

main.c
#include <stdio.h>

extern int *a;

int main(void)
{
    foo();
    printf("main\taddress of a : %x\n", a);
    printf("main\tvalue of a[0] : %x\n", a[0]);

    return 0;
}

and the result output:

foo address of a:804a014
foo value of a[0]:3
main    address of a : 3
Segmentation fault (core dumped)

why?

like image 258
Victor S Avatar asked Jun 23 '12 08:06

Victor S


People also ask

When should I use extern in C?

the extern keyword is used to extend the visibility of variables/functions. Since functions are visible throughout the program by default, the use of extern is not needed in function declarations or definitions. Its use is implicit. When extern is used with a variable, it's only declared, not defined.

Is extern necessary in C?

You do not necessarily "need" extern for variables. When C was invented Unix linkers were also written, and they advanced the art in unheralded but clever ways. One contribution was defining all symbols as small "common blocks".

Can you use extern C in C?

By declaring a function with extern "C" , it changes the linkage requirements so that the C++ compiler does not add the extra mangling information to the symbol. This pattern relies on the presence of the __cplusplus definition when using the C++ compiler. If you are using the C compiler, extern "C" is not used.

Is extern keyword needed?

“extern” keyword is used to extend the visibility of variables/functions(). Since functions are visible through out the program by default. The use of extern is not needed in function declaration/definition.


2 Answers

The type of a is int[2], not int*. Try again with

extern int a[2];

The C compiler cannot type-check across source files. Therefore, when you say int* a, the compiler will assume you're telling the truth, use pointer semantics, and will not issue any compiler error.

There are subtle difference between arrays and pointers. Let's assume a 32-bit system. Then the content of "a" will be distributed like this:

    a
0x100       0x104      0x108   ← address
    +-----------+----------+
    |         3 |        2 |   ← content
    +-----------+----------+

When a is an array,

  • The value of the expression a is will be converted to the address of a. Therefore, when you print a, you will get its address, i.e. "0x100".
  • The operation a[n] in C is equivalent to *(a + n), i.e. advance the address a by n units, and then dereference it to get the content. Therefore, a[0] is equivalent to *0x100, which returns the content at 0x100, i.e. "3".

When a is a pointer,

  • The "value" of a is the content at the provided address. In fact this is the norm, the array type is a special case. Therefore, when you print a, you will get the content at that address, i.e. "3".
  • The operation a[n] is still *(a + n). Therefore, a[0] is equivalent to *3, which causes segmentation fault because the address "3" is invalid.
like image 123
kennytm Avatar answered Oct 01 '22 21:10

kennytm


You have to use consistent types for objects declared across different translation units.

Given int a[] = {2, 3};, either of the declarations extern int a[]; or extern int a[2]; would be compatible whereas extern int *a; would not as pointers and arrays are completely separate types.

The one thing special about arrays is the when the name of an array appears in any expression context other than as an operand to "address of" (unary &) or sizeof, they are automatically converted to a pointer to their first element. This is what provides the syntax compatibility between arrays and pointers, but they are not the same type.

Consider these two functions for a commented example. Note that the expression a is converted to a pointer to its first element in the second (and technically third) printf of the first function, but not in the first printf where it is the operand to &.

#include <stdio.h>

void print_array_info(void)
{
    extern int a[];
    printf("address of a:  %p\n", (void*) &a);   // prints address of a
    printf(" converted a:  %p\n", (void*) a);    // prints address of a[0]
    printf("value of a[0]: %x\n", a[0]);         // prints value of a
}

void print_pointer_info(void) {
    extern int a[];
    int *b = a; // == &a[0]

    printf("address of b:  %p\n", (void*) &b);  // prints address of b
    printf("  value of b:  %p\n", (void*) b);   // prints value of b (== &a[0])
    printf("value of b[0]: %x\n", b[0]);        // prints value of b[0] (== a[0])
}

Note that I use %p to print pointers and explicitly cast to void*.

like image 26
CB Bailey Avatar answered Oct 01 '22 22:10

CB Bailey