0

I'm writing a program that must normalize audio *.wav file. There is a task "to display header's data": ChunkId, ChunkSize and so on.

I want to make a function named display_hdr (In order to have less code in the main.c file, so it will become esier to read this code). To do this I have to pass this function header's variable (variable of type header) as argument, but it writes

functions.h|1|error: unknown type name 'header'|

main.c:

typedef struct FMT
{
    char        SubChunk1ID[4];
    int         SubChunk1Size;
    short int   AudioFormat;
    short int   NumChannels;
    int         SampleRate;
    int         ByteRate;
    short int   BlockAlign;
    short int   BitsPerSample;
} fmt;

typedef struct DATA
{
    char        Subchunk2ID[4];
    int         Subchunk2Size;
    int         Data[];
} data;

typedef struct HEADER
{
    char        ChunkID[4];
    int         ChunkSize;
    char        Format[4];
    fmt         S1;
    data        S2;
} header;

Header's variable was declared in this way:

header hdr;

And now, when I try to pass hdr to my function it prints an error:

functions.h|1|error: unknown type name 'header'|

functions.h

void display_hdr( header hdr )
{
    printf("\n*********************************\n");
    printf("WAVE file's metadata:\n\n");

    printf("%4.4s\n",  hdr.ChunkID   );
    printf("%d\n",     hdr.ChunkSize );
    printf("%4.4s\n",  hdr.Format    );

    printf("%4.4s\n",  hdr.S1.SubChunk1ID   );
    printf("%d\n",     hdr.S1.SubChunk1Size );
    printf("%d\n",     hdr.S1.AudioFormat   );
    printf("%d\n",     hdr.S1.NumChannels   );
    printf("%d\n",     hdr.S1.SampleRate    );
    printf("%d\n",     hdr.S1.ByteRate      );
    printf("%d\n",     hdr.S1.BlockAlign    );
    printf("%d\n",     hdr.S1.BitsPerSample );

    printf("%4.4s\n",  hdr.S2.Subchunk2ID   );
    printf("%d\n",     hdr.S2.Subchunk2Size );   /// SAMPLES' SIZE
    printf("\n*********************************\n");
    return;
}

So, how to pass a variable of your own (non-standard) type to a function as an argument?

yulian
  • 1,601
  • 3
  • 21
  • 49
  • 3
    did you put definition of `header` before your function or included proper header file? – taocp May 18 '13 at 18:38
  • 3
    Note also that passing by value may result in [slicing](http://stackoverflow.com/questions/2432683/what-does-slicing-mean-in-c) due to the variable-length array `Data`. – Raymond Chen May 18 '13 at 18:41
  • @taocp, 1 - function's prototype; 2 - struct header; 3 - declaration of hdr-variable (of type header); 4 - hdr gets data from the file (this works correctly); 5 - THIS function. – yulian May 18 '13 at 18:47
  • @taocp, for the **1** - function's prototype: `:warning: parameter names (without types) in function declaration [enabled by default]|` – yulian May 18 '13 at 18:48
  • 2
    @Julian: The compiler needs to see the `struct` definition *before* the prototype. – Jon May 18 '13 at 18:49
  • re: your query, Julian; it is fine to accept your own answer, if you honestly feel it's the best one. Kudos for wanting to be fair to those who put in effort otherwise, though. – Andrew Barber May 18 '13 at 20:58
  • @Jon, maybe.. But in my case it doesn't help. :( – yulian May 20 '13 at 07:49

3 Answers3

2

"The scope of global variables can be restricted by carefully placing the declaration. They are visible from the declaration until the end of the current source file."

There is no problem on this subject now ( no warning or error ). I just moved a definition of the struct (type) from main.c to function.c (where a variable header of type hdr was declared).

function.h

typedef struct FMT
{
    char        SubChunk1ID[4];
    int         SubChunk1Size;
    short int   AudioFormat;
    short int   NumChannels;
    int         SampleRate;
    int         ByteRate;
    short int   BlockAlign;
    short int   BitsPerSample;
} fmt;

typedef struct DATA
{
    char        Subchunk2ID[4];
    int         Subchunk2Size;
    int         Data[];
} data;

typedef struct HEADER
{
    char        ChunkID[4];
    int         ChunkSize;
    char        Format[4];
    fmt         S1;
    data        S2;
} header;     /* A `header` type created. */

header hdr;   /* After a `header`type was created. */

void display_hdr( header hdr )
{
    printf("\n*********************************\n");
    printf("WAVE file's metadata:\n\n");

    printf("%4.4s\n",  hdr.ChunkID   );
    printf("%d\n",     hdr.ChunkSize );
    printf("%4.4s\n",  hdr.Format    );

    printf("%4.4s\n",  hdr.S1.SubChunk1ID   );
    printf("%d\n",     hdr.S1.SubChunk1Size );
    printf("%d\n",     hdr.S1.AudioFormat   );
    printf("%d\n",     hdr.S1.NumChannels   );
    printf("%d\n",     hdr.S1.SampleRate    );
    printf("%d\n",     hdr.S1.ByteRate      );
    printf("%d\n",     hdr.S1.BlockAlign    );
    printf("%d\n",     hdr.S1.BitsPerSample );

    printf("%4.4s\n",  hdr.S2.Subchunk2ID   );
    printf("%d\n",     hdr.S2.Subchunk2Size );   /// SAMPLES' SIZE
    printf("\n*********************************\n");
    return;
}

PS

Of course I could pass a pointer to a function, but I'd like to pass variable. There is no need to do this thought it is better (economy of memory).

The problem was because of misunderstanding (poor/bad understanding) of 'scope' properly.

PSS

Maybe, Andrew W's right in some way, but that doesn't solve current problem. That is quite another type of problem. But it is worth reading too!

yulian
  • 1,601
  • 3
  • 21
  • 49
1

Is there a reason not to pass a pointer? Doing so will probably give better performance. Besides that, make sure the struct is defined before the prototype. Also, you may want to see Passing struct to function

Community
  • 1
  • 1
Andrew W
  • 4,530
  • 1
  • 16
  • 16
0

Your code simplified inside the main source-code module behaves as expected...

/* your typedef's go here */
/* definition of display_hdr() goes here */

int main( void )
{
    header hdr = {0};   /* near initialization: DO NOT RELY ON THAT */
    display_hdr( hdr );
    exit(0);
}

*please note that the near initialization is just for brevity in this particular example, do not rely on it in real code.

This gives the following output...

*********************************
WAVE file's metadata:


0


0
0
0
0
0
0
0

0

*********************************

So check that your code uses stuff in their appropriate order.

On a side note, for performance reasons you may want to re-write display_hdr()defining it to accept a pointer to header, like so...

void display_hdr( const header *hdr )
{
    /* sanity check */
    if ( NULL == hdr ) {
        fprintf( stderr, "*** NULL pointer argument caught when calling: %s()\n", __func__ );
        return;
    }

    printf("\n*********************************\n");
    printf("WAVE file's metadata:\n\n");

    printf("%4.4s\n",  hdr->ChunkID   );
    printf("%d\n",     hdr->ChunkSize );
    printf("%4.4s\n",  hdr->Format    );

    printf("%4.4s\n",  hdr->S1.SubChunk1ID   );
    printf("%d\n",     hdr->S1.SubChunk1Size );
    printf("%d\n",     hdr->S1.AudioFormat   );
    printf("%d\n",     hdr->S1.NumChannels   );
    printf("%d\n",     hdr->S1.SampleRate    );
    printf("%d\n",     hdr->S1.ByteRate      );
    printf("%d\n",     hdr->S1.BlockAlign    );
    printf("%d\n",     hdr->S1.BitsPerSample );

    printf("%4.4s\n",  hdr->S2.Subchunk2ID   );
    printf("%d\n",     hdr->S2.Subchunk2Size );   /// SAMPLES' SIZE
    printf("\n*********************************\n");

    return;
}

The sanity check ensures that the function will not crash if it is called with a NULL argument, although __func__ is a C99 addition. If you are using an older standard it may be available as an extension (or just hardcode the name of the function ;) )

Your main() function should now pass a pointer to a header object into display_hdr(), or to keep it simple in this example just the address of hdr, something like that...

int main( void )
{
    header hdr = {0};   /* near initialization: DO NOT RELY ON THAT */
    display_hdr( &hdr );
    exit(0);
}
Harry K.
  • 560
  • 3
  • 7
  • My output in quite good: `Enter the names of input and output files including file extension: in.wav out.wav ********************************* WAVE file's metadata: RIFF 27163138 WAVE fmt 16 1 2 44100 88200 2 8 data 27163102 *********************************` Sorry, I don't understand about output like: `0 0 0 0 0 0 (and so on)` ... Is there any reason of such an output? – yulian May 18 '13 at 19:27
  • I'm sorry, I don't understand what you are saying here. I was referring to the output of the sample code I demonstrated. – Harry K. May 18 '13 at 19:32
  • Oh, I think I got what your comment means. Those 0s at the output of my example, are due to the near initialization of `hdr`. It's a quick hack to set all the fields of the `hdr` variable to their zero values (something like using `memset()` on it). Since `hdr` is a `struct`, the proper way of initializing it would be by listing explicitly the values of all its fields, inside the curly braces: [see here](http://stackoverflow.com/questions/330793/how-to-initialize-a-struct-in-ansi-c99) for some examples (since C99 you may use name-value pairs). – Harry K. May 18 '13 at 19:52
  • I appreciate your help. But I'm good with variable hdr. I can accaee to any field (chunk, subchunk and so on ...) Maybe, I didn't understand you again..? – yulian May 18 '13 at 19:56
  • In my example, the line `header hdr = {0};` defines the `hdr` variable and initializes its memory to zero's. So the output produced by calling `display_hdr(hdr);` at the next line gives all those 0s on your screen. But this is kinda off-topic, it was just some additional info ;) What's more important imho is to pass the address of `hdr` into your functions (this means you have to re-write them) because it saves you memory and in many cases it also improves speed. – Harry K. May 18 '13 at 20:06