According to the gcc manual, weak means:


The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.


Better explained with an example:

[wh5a@pri-035 tmp]$ cat weak.c
extern void foo() __attribute__((weak));

int main() {
if (foo) foo();
}
[wh5a@pri-035 tmp]$ cat foo.c
void foo() {
printf("in foo.\n");
}
[wh5a@pri-035 tmp]$ cat strong.c
extern void foo() ;

int main() {
if (foo) foo();
}
[wh5a@pri-035 tmp]$ cc weak.c
[wh5a@pri-035 tmp]$ ./a.out
[wh5a@pri-035 tmp]$ cc strong.c
/tmp/cchyRi5i.o: In function `main':
/tmp/cchyRi5i.o(.text+0x7): undefined reference to `foo'
/tmp/cchyRi5i.o(.text+0x10): undefined reference to `foo'
collect2: ld returned 1 exit status
[wh5a@pri-035 tmp]$ cc weak.c foo.c
[wh5a@pri-035 tmp]$ ./a.out
in foo.


See?
When the "foo" is declared to be weak, its definition can be omitted, or replaced by different libraries, featuring kind of "link-time binding". The linker will fill in 0 for undefined weak symbols.