The structure I am speaking of is the very last one. I get segmentation faults when I try to use it, and when I use sizeof to get its size 218369176 is returned.
typedef struct
{
unsigned long a1; /* Last structure in group. */
unsigned long a2; /* Next structure in group. */
char rc; /* Representing character. */
short st; /* Type of structure (purpose). */
short pl; /* Privilege level required to alter. */
short vt; /* Type of value (short, char, int, long, float, double, void*). */
union
{
short s;
char c;
int i;
long l;
float f;
double d;
void* p;
} un; /* Union containing values to be stored. */
} index_struct; /* Structure composing a table tree. */
typedef struct
{
unsigned long sr; /* Script return value. */
unsigned long ir; /* Interpreter return value. */
unsigned long lc; /* Execution counter (text division interpreter stopped at). */
short ai; /* Action identifier (current status of interpretation). */
short pr; /* Script privilege information. */
char st[65536 /* Change SCRIPT_TEXT_SIZE with this. */]; /* Segment containing script text. */
index_struct lt[65536 /* Change LOCAL_TREE_SIZE with this. */]; /* Segment containing local tree. */
} script_struct; /* Structure containing script state information and variables. */
typedef struct
{
unsigned long us; /* Number of unjoined scripts. */
unsigned long sn; /* Number of running scripts. */
short es; /* Environment status. */
script_struct sl[100 /* Change MAX_NUMBER_SCRIPTS with this. */]; /* Segment containing script list. */
index_struct gt[65536 /* Change GLOBAL_TREE_SIZE with this. */]; /* Segment containing global tree. */
} environment_struct;
EDIT: by popular request, here is the entire source code file.
/*
* BY: Charles Edwin Swain the 3rd.
* LANGUAGES: C and (if I ever comment out certain sections of code) x86 Assembly.
*/
#include <stdio.h>
/*
#include <stdint.h>
const uint8_t CPUID_UNSPECIFIED = 0;
const uint8_t CPUID_SUPPORTED = 1;
const uint8_t CPUID_UNSUPPORTED = 2;
typedef struct
{
uint32_t maximum_standard_level;
uint32_t raw_vendorid[4];
uint32_t raw_processortypeORfamilyORmodelORstepping;
uint32_t num_extendedfamily;
uint32_t num_extendedmodel;
uint32_t num_type;
uint32_t num_family;
uint32_t
uint32_t raw_brandidORCLUFLUSHORCPUcountORAPICID;
uint32_t raw_featureflags_A;
uint32_t raw_featureflags_B;
uint8_t features[64];
} CPUID_struct;
*/
/* These constants are associated with certain hard coded limits, and all must be the same to ensure proper functionality. */
const unsigned long SCRIPT_TEXT_SIZE = 65536; /* Size of segment containing script text. */
const unsigned long GLOBAL_TREE_SIZE = 65536; /* Size of segment composing global tree. */
const unsigned long LOCAL_TREE_SIZE = 65536; /* Size of segments composing local trees. */
const unsigned long MAX_NUMBER_SCRIPTS = 100; /* Maximum number of running scripts in an environment. */
typedef struct
{
unsigned long a1; /* Last structure in group. */
unsigned long a2; /* Next structure in group. */
char rc; /* Representing character. */
short st; /* Type of structure (purpose). */
short pl; /* Privilege level required to alter. */
short vt; /* Type of value (short, char, int, long, float, double, void*). */
union
{
short s;
char c;
int i;
long l;
float f;
double d;
void* p;
} un; /* Union containing values to be stored. */
} index_struct; /* Structure composing a table tree. */
typedef struct
{
unsigned long sr; /* Script return value. */
unsigned long ir; /* Interpreter return value. */
unsigned long lc; /* Execution counter (text division interpreter stopped at). */
short ai; /* Action identifier (current status of interpretation). */
short pr; /* Script privilege information. */
char st[65536 /* Change SCRIPT_TEXT_SIZE with this. */]; /* Segment containing script text. */
index_struct lt[65536 /* Change LOCAL_TREE_SIZE with this. */]; /* Segment containing local tree. */
} script_struct; /* Structure containing script state information and variables. */
typedef struct
{
unsigned long us; /* Number of unjoined scripts. */
unsigned long sn; /* Number of running scripts. */
short es; /* Environment status. */
script_struct sl[100 /* Change MAX_NUMBER_SCRIPTS with this. */]; /* Segment containing script list. */
index_struct gt[65536 /* Change GLOBAL_TREE_SIZE with this. */]; /* Segment containing global tree. */
} environment_struct; /* Structure containing environment state information and global tree. */
/*
* Function definition and calling conventions follow:
*
* - All non-interpreter functions should be called through a wrapper function.
* - This wrapper function's address is specified through the p field of an index_struct in the global tree.
* - The return items of the function are specified through the global tree, under 'f_retu'.
* - The arguments to the function are specified through the global tree, under 'f_argv'.
* - The number of arguments to the function are specified through the global tree, under 'f_argc'.
* - Before calling the wrapper function, these fields and the environment status are appropriately set.
* - The wrapper function takes a pointer to the segment containing the global tree as an argument (outside the interpreter).
* - The wrapper function sorts through the arguments and calls the appropriate function it is wrapping.
* - Once this function returns, it sets any actual interpreter buffers accordingly.
* - What is meant by the above is that the wrapper function will use temporary buffers in the call to the function, then transfer data over according to global tree arguments.
* - Once the wrapper function returns, the calling (interpreter) code should copy all data from the return to an appropriate location and wipe all involved tables (for security).
* - This entire state is uninterruptable by interruption code from the moment the interpreter begins the call to after the interpreter finishes wiping data.
* - The above does not include signals, and only describes with regard to the interpreter auto returning after interpreting some input.
*
*/
/* Creates a fresh interpreter environment. */
int ecreate(environment_struct* environment)
{
if (environment == NULL)
{
return -1;
}
else
{
if (environment->es != 0)
{
return -2;
}
else
{
environment->us = 0;
environment->sn = 0;
environment->es = 1;
return 0;
}
}
}
/* Cleans up and shuts down an interpreter environment. */
int edestroy(environment_struct* environment)
{
if (environment == NULL)
{
return -1;
}
else
{
if (environment->es == 0)
{
return -2;
}
else
{
environment_struct environment_B;
*environment = environment_B;
return 0;
}
}
}
/* Main function. */
int main(int argc, char** argv)
{
/* This is where the sizeof is. Works fine when code behind next comment is not commented in.*/
printf("%lu\n", sizeof(environment_struct));
/* Next comment. */
environment_struct environment;
int r_ecreate, r_edestroy;
r_ecreate = ecreate(&environment);
r_edestroy = edestroy(&environment);
printf("%d, %d\n", r_ecreate, r_edestroy);
return 0;
}
index_struct will have a size of 24 bytes on your average 32-bit system (or 32 bytes on your average 64-bit system).
script_struct will have a size of 1,638,416 bytes (1.6 MB) on your average 32-bit system (or 2,162,720 bytes (2.16 MB) on your average 64-bit system).
environment_struct will have a size of 165,414,476 (165.4 MB) on your average 32-bit system (or 218,369,176 bytes (218.3 MB) on your average 64-bit system (which is the size you're seeing)).
That is an insanely large size for a struct, and very well might crash your system (particularly if you use it on the stack). If you allocate several environment_structs (on the heap), you could very well run out of memory.
So yeah, they're too large. Waaay too large.
Edit: Yup, you're declaring a environment_struct on the stack. A struct that big is insane for the stack.
Just a small addendum to Cornstalks' answer. On a 64-bit Intel system, the sizes would be, according to my calculations:
sizeof(index_struct) = 32
sizeof(script_struct) = 2162716
sizeof(environment_struct) = 218368770
Therefore, the result you get from sizeof are correct.
In your code, you are putting environment_struct on the stack. The stack space is usually fixed and quite limited - on my system it's just 8 MiB. If you really want to use such a gigantic structure, you should allocate the memory for it with malloc(). A better approach, which would also remove the rather arbitrary limit of 65536 scripts, would be to store a linked list or array of scripts allocated with malloc(), instead of reserving a fixed amount of space.
Related
I am having some trouble starting my program. I'm new to this. I have done some research and found some resources, but I have trouble applying it to the code. It is mostly based on pointers and structures.
I mainly need help with learning how to store the data in the struct, and how to initialize everything.
The program is supposed to find the frequency of characters in a file. I need to use dynamic memory allocation. And use a dynamically allocated array of pointers to store the characters and frequencies. I am supposed to use malloc() to allocate the array and realloc() to increase the size of the array to insert more elements. But I have no idea how to do this.
The program uses these functions-
• charInCFStruct:which returns the index of charfreq struct which has the char c stored in its member variable next. If none of the charfreq structs contains c then it has to return -1.
• printCFStruct: Prints the contents of all of the charfreq structs.
• freeCFStruct: Frees all of the charfreq structs and then frees the pointer
to the structs.
Down below is what I know is right so far. I thought it would be easier to start again from there. I am not asking for code exactly, just some help with the topics I need to do this, and a push in the right direction. Thank you!
#include <stdio.h>
#include <stdlib.h>/*
* struct for storing a char and the number of times it appears in a provided text */
struct charfreq
{
int count;
char next;
};
typedef struct charfreq charfreq;
/*
* Returns the index of charfreq struct which has the char c stored in its member variable next.
* If none of the charfreq structs contains c then it returns -1.
*/
int charInCFStruct(charfreq **cfarray, int size, char c){
}
/*
* Prints the contents of all of the charfreq structs.
*/
void printCFStruct(charfreq **cfarray, int size){
}
/*
* Frees all of the charfreq structs and then frees the pointer to the structs.
*/
void freeCFStruct(charfreq **cfarray, int size){
}
int main(void)
{
charfreq **cfarray;
FILE *inputfile;
char next;
int size = 10; /* used initial value of 10 but any positive number should work */
int i = 0;
int pos;
/* open file to read from */
inputfile = fopen("chars.txt", "r");
if(inputfile == NULL)
printf("chars.txt could not be opened. Check that the file is in the same directory as you are running this code. Ensure that its name is chars.txt.\n\n");
/* allocate space for pointers to char frequency structs */
cfarray = (charfreq**)malloc(size*sizeof(charfreq*));
/* read in chars until the end of file is reached */
while(fscanf(inputfile, "%c", &next) != EOF){
/* fill in code to fill structs with data being read in */
/* call to increase space after changing size */
cfarray = realloc(cfarray,size*sizeof(charfreq*));
}
/* print out char frequency structs */
printCFStruct(cfarray,i);
/* free all char frequency structs */
freeCFStruct(cfarray,i);
/* close the file we opened earlier */
fclose(inputfile);
return 0;
}
My struct looks like this:
struct tlv_msg
{
uint8_t datatype; //type of data
/* data stored in a union */
union{
int32_t s32val; /* int */
int64_t s64val; /* long long */
uint32_t u32val; /* unsigned int */
uint64_t u64val; /* unsigned long long */
char* strval; /* string */
unsigned char* binval; /* any binary data */
};
uint32_t bytelen; /* no. bytes of union/data part */
};
This struct uses a union to hold some different data types. I have an alloc function which allocates memory for the struct on the heap. Am I correct in thinking that if I am allocating for an integral type (ie the first four types above in union) I only need to allocate as follows:
tlv_msg* msg = malloc(sizeof(tlv_msg));
sizeof(tlv_msg) returns 24. I presume this is enough bytes to hold the largest data type in the union plus the other data members. (not sure why 24 - can someone explain?).
But if the data type to be stored is a pointer type, eg char* then I then need to also do this:
msg->strval = (char*)malloc(sizeof(string_length+1);
That would make sense to me and that seems to work but just wanted to check.
That's perfectly right.
That said, you may want to create helper functions, to help you dealing with this.
For instance:
tlv_msg * new_tlv_msg( void );
/* There, you need to free struct members, if applicable */
void delete_tlv_msg( tlv_msg * msg );
/* Here you may copy your string, allocating memory for it */
tlv_msg_set_strval( tlv_msg * msg, char * str );
Implementation may be (basic, of course)
tlv_msg * new_tlv_msg( void )
{
return calloc( sizeof( tlv_msg ), 1 );
}
void delete_tlv_msg( tlv_msg * msg )
{
if( msg->strval != NULL )
{
free( msg-strval );
}
free( msg );
}
tlv_msg_set_strval( tlv_msg * msg, char * str )
{
if( msg->strval != NULL )
{
free( msg-strval );
}
msg->strval = strdup( str );
}
Yes, you are correct about having to perform two memory allocation steps, the first for the struct and the second for the character string.
Unless this is an embedded system where memory space is at a premium, one way to get around this is to decide on a maximum string size. Yes, that does waste memory, if, for example, you only usually have 10 character or fewer strings and allocate for say 25 characters.
#define WORKING_BUF_LEN 1024
struct tlv_msg
{
uint8_t datatype; //type of data
/* data stored in a union */
union{
int32_t s32val; /* int */
int64_t s64val; /* long long */
uint32_t u32val; /* unsigned int */
uint64_t u64val; /* unsigned long long */
char strval[WORKING_BUF_LEN={0}; /* string */
unsigned char* binval; /* any binary data */
};
uint32_t bytelen; /* no. bytes of union/data part */
};
You could also do your own memory management to avoid fragmenting the heap if you plan on having many of these structs and hence many char* pointers, but that requires a lot of work. You'd overwrite new with a macro and assign pre-allocated storage to your pointer and then do storage allocation book keeping. Don't do it unless you have to.
was reading Robert Love's book, chapter 5 on syscalls, and found this simple example a bit questionable:
asmlinkage long sys_silly_copy(unsigned long *src, unsigned long *dst, unsigned long len)
{
unsigned long buf;
if (copy_from_user(&buf, src, len))
return -EFAULT;
...
}
As we see 'buf' is object of type 'unsigned long' and defined on the kernel stack, i.e. its initial value is likely garbage. Anyway is it valid to copy 'len' bytes in the stack where buf is, i.e. it could overwrite something useful? Perhaps this is fine only for this particular example?
It is very questionable. In fact, it's downright dangerous. I'll give the author the benefit of the doubt here since they're just trying to show how copy_from_user and copy_to_user work but they really should have provided an example that wasn't so dangerous.
Especially since the book waxes lyrical about how you must be extra careful:
System calls must carefully verify all their parameters to ensure that they are valid and
legal.The system call runs in kernel-space, and if the user can pass invalid input into the
kernel without restraint, the system’s security and stability can suffer.
and then provides a means for the user to totally annihilate the kernel :-)
The text from the copy I have states:
Let’s consider an example system call that uses both copy_from_user() and copy_to_user().This syscall, silly_copy(), is utterly worthless; it copies data from its first parameter into its second.This is suboptimal in that it involves an intermediate and extraneous copy into kernel-space for no gain. But it helps illustrate the point.
/*
* silly_copy - pointless syscall that copies the len bytes from
* ‘src’ to ‘dst’ using the kernel as an intermediary in the copy.
* Intended as an example of copying to and from the kernel.
*/
SYSCALL_DEFINE3(silly_copy,
unsigned long *, src,
unsigned long *, dst,
unsigned long len)
{
unsigned long buf;
/* copy src, which is in the user’s address space, into buf */
if (copy_from_user(&buf, src, len))
return -EFAULT;
/* copy buf into dst, which is in the user’s address space */
if (copy_to_user(dst, &buf, len))
return -EFAULT;
/* return amount of data copied */
return len;
}
Other than the catastrophic failure of not checking parameters, I'm pretty certain the last parameter of the SYSCALL_DEFINE3 is missing a comma (though that would just be a typo).
A far better example, without having to allocate arbitrary memory, would be along the lines of:
SYSCALL_DEFINE3(silly_copy,
unsigned long *, src,
unsigned long *, dst,
unsigned long, len)
{
unsigned long buf[64]; /* Buffer for chunks */
unsigned long lenleft = len; /* Remaining size */
unsigned long chunklen = sizeof(buf); /* Initial chunk length */
/* Loop handling chunk sizes */
while (lenleft > 0) {
/* Change chunk length on last chunk */
if (lenleft < chunklen) chunklen = lenleft;
/* copy src(user) to buf(kernel) then dst(user) */
if (copy_from_user(buf, src, chunklen)) return -EFAULT;
if (copy_to_user(dst, buf, chunklen)) return -EFAULT;
/* Adjust pointers and remaining size */
src += chunklen; dst += chunklen; lenleft -= chunklen;
}
/* return amount of data copied */
return len;
}
Anyone trying to implement that system call would be well advised to steer away from that particular sample in the book, although I suppose, at a bare minimum, it will give you some good kernel debugging experience :-)
int init_module(void)
{
mempool_t *mempool;
struct kmem_cache *kmem_cache;
void *p0 , *p1;
kmem_cache = kmem_cache_create("Ashrama" ,100 , 0 ,SLAB_PANIC ,NULL);
mempool = mempool_create(4 , mempool_alloc_slab , mempool_free_slab , kmem_cache);
p0 = mempool_alloc(mempool, SLAB_PANIC);
p1 = mempool_alloc(mempool , SLAB_PANIC);
strcpy(p0 , "Ranjan.B.M");
strcpy(p1 , "Mithun.V");
mempool_free( p0 , mempool);
printk(KERN_ALERT"%s",p0);
printk(KERN_ALERT"%s",p1);
}
I'm reading binary data from a file, specifically from a zip file. (To know more about the zip format structure see http://en.wikipedia.org/wiki/ZIP_%28file_format%29)
I've created a struct that stores the data:
typedef struct {
/*Start Size Description */
int signatute; /* 0 4 Local file header signature = 0x04034b50 */
short int version; /* 4 2 Version needed to extract (minimum) */
short int bit_flag; /* 6 2 General purpose bit flag */
short int compression_method; /* 8 2 Compression method */
short int time; /* 10 2 File last modification time */
short int date; /* 12 2 File last modification date */
int crc; /* 14 4 CRC-32 */
int compressed_size; /* 18 4 Compressed size */
int uncompressed_size; /* 22 4 Uncompressed size */
short int name_length; /* 26 2 File name length (n) */
short int extra_field_length; /* 28 2 Extra field length (m) */
char *name; /* 30 n File name */
char *extra_field; /*30+n m Extra field */
} ZIP_local_file_header;
The size returned by sizeof(ZIP_local_file_header) is 40, but if the sum of each field is calculated with sizeof operator the total size is 38.
If we have the next struct:
typedef struct {
short int x;
int y;
} FOO;
sizeof(FOO) returns 8 because the memory is allocated with 4 bytes every time. So, to allocate x are reserved 4 bytes (but the real size is 2 bytes). If we need another short int it will fill the resting 2 bytes of the previous allocation. But as we have an int it will be allocated plus 4 bytes and the empty 2 bytes are wasted.
To read data from file, we can use the function fread:
ZIP_local_file_header p;
fread(&p,sizeof(ZIP_local_file_header),1,file);
But as there're empty bytes in the middle, it isn't read correctly.
What can I do to sequentially and efficiently store data with ZIP_local_file_header wasting no bytes?
In order to meet the alignment requirements of the underlying platform, structs may have "padding" bytes between members so that each member starts at a properly aligned address.
There are several ways around this: one is to read each element of the header separately using the appropriately-sized member:
fread(&p.signature, sizeof p.signature, 1, file);
fread(&p.version, sizeof p.version, 1, file);
...
Another is to use bit fields in your struct definition; these are not subject to padding restrictions. The downside is that bit fields must be unsigned int or int or, as of C99, _Bool; you may have to cast the raw data to the target type to interpret it correctly:
typedef struct {
unsigned int signature : 32;
unsigned int version : 16;
unsigned int bit_flag; : 16;
unsigned int compression_method : 16;
unsigned int time : 16;
unsigned int date : 16;
unsigned int crc : 32;
unsigned int compressed_size : 32;
unsigned int uncompressed_size : 32;
unsigned int name_length : 16;
unsigned int extra_field_length : 16;
} ZIP_local_file_header;
You may also have to do some byte-swapping in each member if the file was written in big-endian but your system is little-endian.
Note that name and extra field aren't part of the struct definition; when you read from the file, you're not going to be reading pointer values for the name and extra field, you're going to be reading the actual contents of the name and extra field. Since you don't know the sizes of those fields until you read the rest of the header, you should defer reading them until after you've read the structure above. Something like
ZIP_local_file_header p;
char *name = NULL;
char *extra = NULL;
...
fread(&p, sizeof p, 1, file);
if (name = malloc(p.name_length + 1))
{
fread(name, p.name_length, 1, file);
name[p.name_length] = 0;
}
if (extra = malloc(p.extra_field_length + 1))
{
fread(extra, p.extra_field_length, 1, file);
extra[p.extra_field_length] = 0;
}
C structs are just about grouping related pieces of data together, they do not specify a particular layout in memory. (Just as the width of an int isn't defined either.) Little-endian/Big-endian is also not defined, and depends on the processor.
Different compilers, the same compiler on different architectures or operating systems, etc., will all layout structs differently.
As the file format you want to read is defined in terms of which bytes go where, a struct, although it looks very convenient and tempting, isn't the right solution. You need to treat the file as a char[] and pull out the bytes you need and shift them in order to make numbers composed of multiple bytes, etc.
The solution is compiler-specific, but for instance in GCC, you can force it to pack the structure more tightly by appending __attribute__((packed)) to the definition. See http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/Type-Attributes.html.
It's been a while since I worked with zip-compressed files, but I do remember the practice of adding my own padding to hit the 4-byte alignment rules of PowerPC arch.
At best you simply need to define each element of your struct to the size of the piece of data you want to read in. Don't just use 'int' as that may be platform/compiler defined to various sizes.
Do something like this in a header:
typedef unsigned long unsigned32;
typedef unsigned short unsigned16;
typedef unsigned char unsigned8;
typedef unsigned char byte;
Then instead of just int use an unsigned32 where you have a known 4-byte vaule. And unsigned16 for any known 2-byte values.
This will help you see where you can add padding bytes to hit 4-byte alignment, or where you can group 2, 2-byte elements to make up a 4-byte alignment.
Ideally you can use a minimum of padding bytes (which can be used to add additional data later as your expand the program) or none at all if you can align everything to 4-byte boundaries with variable-length data at the end.
Also, the name and extra_field will not contain any meaningful data, most likely. At least not between runs of the program, since these are pointers.
i got a question about unsigned char array.
How can i store an integer in the array continually?
for example, i need to store 01011 to the array first. Then i need to store 101, how can i stored as 01011101 in the array?
thanks for your help!
Store 01011 first. You'll get value 00001011. Then when you want to store three more bits, perform a left shift by three positions (you'll get 01011000) and make OR with 00000101, you'll get 01011101. However, doing it this way you have to know definitely that you had only five bits filled after first assignment.
Obviously, you'll need to resize the array as it grows. Dynamic memory allocation/reallocation is a way to go, probably. Pay attention to choosing a right reallocation strategy.
Apart from that, you may want to look at C++ STL containers if you are not limited only to C.
You should write an abstract data type called bitstream for this purpose. It could have the following interface:
This is file bitstream.h:
#ifndef BITSTREAM_H
#define BITSTREAM_H
typedef struct bitstream_impl bitstream;
struct bitstream_impl;
/**
* Creates a bit stream and allocates memory for it. Later, that memory
* must be freed by calling bitstream_free().
*/
extern bitstream *bitstream_new();
/**
* Writes the lower 'bits' bits from the 'value' into the stream, starting with
* the least significand bit ("little endian").
*
* Returns nonzero if the writing was successful, and zero if the writing failed.
*/
extern int bitstream_writebits_le(bitstream *bs, unsigned int value, unsigned int bits);
/**
* Writes the lower 'bits' bits from the 'value' into the stream, starting with
* the most significand bit ("big endian").
*
* Returns nonzero if the writing was successful, and zero if the writing failed.
*/
extern int bitstream_writebits_be(bitstream *bs, unsigned int value, unsigned int bits);
/**
* Returns a pointer to the buffer of the bitstream.
*
* The returned pointer remains valid until the next time that one of the
* bitstream_write* functions is called. The returned buffer must not be
* modified. All bits in the buffer that have not yet been written are zero.
* (This applies only to the last byte of the buffer.) Each byte of the buffer
* contains at most 8 bits of data, even if CHAR_BITS is larger.
*/
extern unsigned char *bitstream_getbuffer(const bitstream *bs);
/**
* Returns the number of bits that have been written to the stream so far.
*/
extern unsigned int bitstream_getsize(const bitstream *bs);
/**
* Frees all the memory that is associated with this bitstream.
*/
extern void bitstream_free(bitstream *bs);
#endif
Then you need to write an implementation for this interface. It should be in a file called bitstream.c. This is left as an excercise.
To use the bitstream should then be pretty simple:
#include "bitstream.h"
static void
die(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
int main(void)
{
bitstream *bs;
unsigned char *buf;
bs = bitstream_new();
if (bs == NULL)
die("bitstream_new");
if (!bitstream_writebits_be(bs, 0x000b, 5))
die("write 5 bits");
if (!bitstream_writebits_be(bs, 0x0005, 3))
die("write 3 bits");
if (bitstream_getsize(bs) != 8)
die("FAIL: didn't write exactly 8 bits.");
buf = bitstream_getbuffer(bs);
if (buf[0] != 0x005dU)
die("FAIL: didn't write the expected bits.");
bitstream_free(bs);
return 0;
}