Thread: Can I create a fileheader using printf?

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485

    Can I create a fileheader using printf?

    Hi,

    I´m trying to create a aiff to wave converter as a way to learn. So far I´m dealing with the header and have set up a couple of structs that holds both a set of names and variables such as file size, sample rate etc. At the moment I´m using printf to create the new header and pass the output to a new file that I can inspect in a hexeditor.

    Code:

    The FORM chunk represents the first 12 bytes in a aiff file.
    Code:
    	// FORM chunk
    
    	typedef struct {
    		char			*ckID;		// 'FORM' 
    		int			ckDataSize;		
    		char			*formType;	// 'AIFF'
    	} FormAIFFChunk;
    
    	int size = 0x3E52; // for testing purpose only! *
    
    
    	// collect size and print FORM chunk
    
    	FormAIFFChunk form = {"FORM", 0x0000, "AIFF"};
    	form.ckDataSize = size; 
    	printf("%s%x%s", form.ckID, form.ckDataSize, form.formType);
    The problem now is that 'size' shows up as a string in the hexeditor and occupy 4 whole bytes, Eventhough it´s a 2 byte value. Is there a way to get around this using printf?

    I did an earlier atempt using arrays and memcpy, but using the structs got a lot more clear.
    Last edited by Subsonics; 01-07-2009 at 12:03 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > Is there a way to get around this using printf?
    It's binary data, so probably no.

    You should be using fwrite() to a file, not printf to stdout.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Hmm, yeah that makes sense I suppose. I was hoping that I could test this part first without having to deal with files directly in the code. I´ll look into fwrite().

    Thanks, Salem.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Subsonics View Post
    Hi,

    I´m trying to create a aiff to wave converter as a way to learn. So far I´m dealing with the header and have set up a couple of structs that holds both a set of names and variables such as file size, sample rate etc. At the moment I´m using printf to create the new header and pass the output to a new file that I can inspect in a hexeditor.

    Code:

    The FORM chunk represents the first 12 bytes in a aiff file.
    Code:
    	// FORM chunk
    
    	typedef struct {
    		char			*ckID;		// 'FORM' 
    		int			ckDataSize;		
    		char			*formType;	// 'AIFF'
    	} FormAIFFChunk;
    I suspect you want this:
    Code:
    		char			ckID[4];		// 'FORM' 
    		int			ckDataSize;		
    		char			formType[4];	// 'AIFF'
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by matsp View Post
    I suspect you want this:
    Code:
    		char			ckID[4];		// 'FORM' 
    		int			ckDataSize;		
    		char			formType[4];	// 'AIFF'
    --
    Mats
    Yes I guess I could use arrays. I came across the use of pointers not so long ago to store strings this way, have no idea how that works though. Do any one of you guys know?

    Also, if I type
    Code:
    char *var = "var";
    char array[4] = {"array"};
    
    printf("%s %s", var, array);
    I get: var array? as a result. Is the questionmark a result of printf printing the closing character of the array?

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    It's the result of you trying to put 5 chars into a 4-char array, and losing an all important \0 to mark the end of the string.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Code:
    char *var = "var";
    char array[4] = {"array"};
    
    printf("%s %s", var, array);
    The array variable should not be allowed (at least not without warning) by the compiler, as it is a 5 character long array. Since you only have 4 elements in the array, that is longer than the space you have allowed for it - not a good idea. Since strings (in C) are defined as a sequence of characters followed by a zero-character (not the '0', but '\0' or 0) - since your 4 character array containing 5 characters does not have any space for this terminating zero, printf will keep going until the next zero that happens to be in memory. In this case you were lucky that it was only one extra character before that happens to be.

    var is a pointer to a character. For use with printf, it makes little difference, but if you were to use it inside a struct, and then use fwrite to store the whole struct to a file, you would find that you are storing the address of the string, rather than the content of the string - which certainly won't work if you read it back with a different program, because that memory will absolutely not contain the string you want.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by Salem View Post
    It's the result of you trying to put 5 chars into a 4-char array, and losing an all important \0 to mark the end of the string.
    Oops, that is a typo I made here actually. I do get the same result with array[5] though.

  9. #9
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by matsp View Post
    var is a pointer to a character. For use with printf, it makes little difference,
    Ok, but why does it work in this example? Where are the two extra characters stored? Is it safe to store strings this way?

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Here is the complete code snippet that get this behaviour BTW.

    Code:
    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	char *test = "test";
    	char array[5] = {"array"};
    
    	printf("test: %s, array: %s\n", test, array);
    
    	return 0;
    }
    When I compile and run this I get:

    test: test, array: array?
    Last edited by Subsonics; 01-07-2009 at 03:39 PM. Reason: Added the output I get

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Subsonics View Post
    Ok, but why does it work in this example? Where are the two extra characters stored? Is it safe to store strings this way?
    It works, because printf gets the address of array, and the address stored in var - both results in the address of a sequence of characters. And as there is a zero SOMEWHERE after the string value "array", the printf stops after writing some "rubbish" (which is the content that happened to be in that location in memory - change your code a bit, and you will get a different result).

    I'm not sure which "two extra characters" you are talking about - do you mean the 'y' from the "array" - it is store immediately after the 4 that you have given. Note however for printf to print "array", you really need 6 characters in your array, since you also need to have space for the terminating zero character - otherwise you will still have the problem that printf continues to print after the end of your string, whatever happens to be at that location, until the next zero it can find - in extreme cases, that could be megabytes of data!!

    Note also that for your AIFF header, you DO NOT want a terminating zero - it is four characters that contain 'A', 'I', 'F' and 'F' - it is technically (from a C standpoint) not a string, and you should not try to print that with %s in printf [without copying to a longer char array (at least 5 long) and putting a zero at position [4] (fifth character)]

    It is safe to store strings in char arrays, as long as they have the right size.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by matsp View Post
    .
    I'm not sure which "two extra characters" you are talking about - do you mean the 'y' from the "array" - it is store immediately after the 4 that you have given.
    I´m talking abot the characters 'a' and 'r' in var, since *var is a pointer to a char I guess there should only be reserved room for one character in this case 'v', still however I´m able to store three characters and print them. The array was a typo I made here, in my code it is 5 char long.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by Subsonics View Post
    Oops, that is a typo I made here actually. I do get the same result with array[5] though.
    You don't have room for any characters there, so all of them are overwriting somebody else's memory.

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Subsonics View Post
    I´m talking abot the characters 'a' and 'r' in var, since *var is a pointer to a char I guess there should only be reserved room for one character in this case 'v', still however I´m able to store three characters and print them. The array was a typo I made here, in my code it is 5 char long.
    But a string in C is a sequence of characters that end with a zero - so pointer to char will point to the FIRST of those characters. In the case of "var" in your code, it will be stored somewhere in the program's memory as a sequence of four characters, 'v', 'a', 'r', '\0' - where this is stored is entirely up to the compiler, but generally strings are (nowadays) stored in a read-only data part of your executable file, and loaded into memory just like the code and any pre-initialized data.

    Note that "char *var" in itself does not allow even ONE character to be stored. It is a place where you can store the ADDRESS of a character - when you initialize that string with "var", it is given the address that the compiler put those characters in.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #15
    Registered User
    Join Date
    Jan 2009
    Posts
    1,485
    Quote Originally Posted by tabstop View Post
    You don't have room for any characters there, so all of them are overwriting somebody else's memory.
    How come? If I create an array to store 5 chars is there another way of doing it? I did like this
    Code:
    char array[5];

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 03-05-2009, 10:25 AM
  2. get keyboard and mouse events
    By ratte in forum Linux Programming
    Replies: 10
    Last Post: 11-17-2007, 05:42 PM
  3. segmentation fault upon reload
    By yabud in forum C Programming
    Replies: 8
    Last Post: 12-18-2006, 06:54 AM
  4. I need help on this particular Linked List problem
    By sangken in forum C Programming
    Replies: 11
    Last Post: 08-06-2006, 12:26 AM
  5. Replies: 4
    Last Post: 04-01-2003, 12:49 AM