5

Here is the minimal C program to reproduce:

#include <alsa/asoundlib.h>
#include <sys/time.h>

int main( void )
{
}

This will compile with gcc -c -o timealsa.o timealsa.c, but if you include the -std=c99 switch, you get a redefinition error:

In file included from /usr/include/sys/time.h:28:0,
                 from timealsa.c:3:
/usr/include/bits/time.h:30:8: error: redefinition of ‘struct timeval’
 struct timeval
        ^
In file included from /usr/include/alsa/asoundlib.h:49:0,
                 from timealsa.c:2:
/usr/include/alsa/global.h:138:8: note: originally defined here
 struct timeval {
        ^

How can I resolve this conflict while still using -std=c99?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Lombard
  • 187
  • 7
  • You should use the minimum standard of main which is **int main(void){return 0;}** – Michi Sep 19 '15 at 19:32
  • Yes, you're right (but that's one more line!) – Lombard Sep 19 '15 at 19:34
  • @Michi the `return 0` is implicit if not present in _C99_ (Whcih this question is tagged with). See: http://stackoverflow.com/questions/4138649/why-is-return-0-optional . The void is a problem though – Michael Petch Sep 19 '15 at 19:36
  • Since the question is focused on the c99 standard I will make it more compliant. – Lombard Sep 19 '15 at 19:38
  • @MichaelPetch I found there that **Returning 0 from main is in C99 § 5.1.2.2.3** – Michi Sep 19 '15 at 19:39
  • Indeed `reaching the } that terminates the main function returns a value of 0`, but we *are* submarining here into an unrelated issue :) – Lombard Sep 19 '15 at 19:42
  • There was about **return 0** and not about **0** or something else. – Michi Sep 19 '15 at 19:43
  • In C99 it is implicit, so if you don't put `return 0` it is implied. This isn't the case for C89/C90 . – Michael Petch Sep 19 '15 at 19:43
  • 1
    And it's a bad idea, IMHO, because `main()` shouldn't be "special". But indeed, this is completely unrelated here. And btw, `int main(void)` is fine, too. –  Sep 19 '15 at 19:44
  • @MichaelPetch Sir, sorry now I understood your point :)). – Michi Sep 19 '15 at 19:49

2 Answers2

5

Since your question suggests you are using GLIBC's time.h there is a way to avoid this by telling it not to define timeval. Include asoundlib.h first then define _STRUCT_TIMEVAL. The one defined in asoundlib.h will be the one that gets used.

#include <alsa/asoundlib.h>
#ifndef _STRUCT_TIMEVAL
#  define _STRUCT_TIMEVAL
#endif
#include <sys/time.h>

int main( void )
{
}
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • This works - so what does `std=c99` bring to the table that makes us then need to explicitly disable sys/time's definition of timeval? – Lombard Sep 19 '15 at 19:47
  • 3
    @Lombard it enforces standards compliance, so redefinitions are illegal. Try `std=c89`, will give you the same result. –  Sep 19 '15 at 19:48
  • 1
    @Lombard : I have made a small alteration to the code to only define _STRUCT_TIMEVAL if it isn't already defined. There are some warning options like `-Wall` that may pick up the redefinition of the define as a problem. – Michael Petch Sep 19 '15 at 19:56
  • GCC doesn't come with a time.h. You probably mean glibc. Depending on the target system, GCC can use any of a number of libc implementations. – rubenvb Jun 03 '17 at 18:07
2

With C99 and later you can't have duplicate definitions of the same struct. The problem is that alsa/asoundlib.h includes alsa/global.h which contains this code:

/* for timeval and timespec */
#include <time.h>

...

#ifdef __GLIBC__
#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE)
struct timeval {
        time_t          tv_sec;         /* seconds */
        long            tv_usec;        /* microseconds */
};

struct timespec {
        time_t          tv_sec;         /* seconds */
        long            tv_nsec;        /* nanoseconds */
};
#endif
#endif

So the Michael Petch's solution won't work - by the time you've included alsa/asoundlib.h it is already too late. The proper solution is to define _POSIX_C_SOURCE (_POSIX_SOURCE is obsolete). There's more information about these macros here and here.

For example you could try -D_POSIX_C_SOURCE=200809L. However, if you do that you'll get errors like this:

/usr/include/arm-linux-gnueabihf/sys/time.h:110:20: error: field ‘it_interval’ has incomplete type
     struct timeval it_interval;
                    ^
/usr/include/arm-linux-gnueabihf/sys/time.h:112:20: error: field ‘it_value’ has incomplete type
     struct timeval it_value;
                    ^
/usr/include/arm-linux-gnueabihf/sys/time.h:138:61: error: array type has incomplete element type
 extern int utimes (const char *__file, const struct timeval __tvp[2])
                                                             ^

This is all a big mess of old C code and macro madness. The only way I got it to work was to give up and use -std=gnu11.

Timmmm
  • 88,195
  • 71
  • 364
  • 509