[sclug] C programming question and date on Linux

lug at assursys.co.uk lug at assursys.co.uk
Sat Oct 25 09:05:36 UTC 2003


On Thu, 10 Apr 2003, Rick Payne wrote:

> --On Thursday, April 10, 2003 4:42 pm +0100 pieter claassen 
> <pieter at openauth.co.uk> wrote:
> 
> > Hello All,
> >
> > Here are two simple questions.
> > 1. Why does C on linux have such cool undocumented data types such as
> > u_int16_y and where are they documented? My Kernighan and Ritchie says
> > nothing about them. How do I know when I write a program which ones I am
> > supposed to use? Also, if I look through the /net/ethernet.h I get the
> > following declaration
> 
> The u_intxx_t types seem to be a semi-standard - and may even be an 
> official one. It helps to be specific when you're typing things that you 
> want to be specific bit-sizes (ie. where 'int' just won't do).

the u_xxx_t types are defined in <linux/types.h> and are typedef'ed from the
definitions in <asm/types.h>

[snip]

> __attribute__((__packed__)) is a gross hack provided by gcc to allow you to 
> break the normal rules 'C' would use when putting things into a structure. 
> Its most commonly used when trying to make a structure that matches a 
> packet or file format, as seen in your example. I use it all the time, but 
> its still a gross hack.

Another common use for them is when you're creating structures to match the
layout of memory-mapped registers. The alternative would be doing something
like

	char *regbase;

	[...]

	regbase=(char *)0xe2007000;

	[...]

	*(regbase+0)=(unsigned short)0xffff;
	*(regbase+2)=(unsigned char)0xee;
	*(regbase+3)=(unsigned int)0xc0edbabe;

Which is even more gross, IMHO (although, to be fair, if I was doing this
'for real', I would #define appropriate constants to allow the
slightly tidier-looking *(regbase+REGISTERA) code).

Similarly, defining datatypes with specific bit-lengths is necessary to
avoid the twin evils of a) having to write registers a character at a time -
some hardware is latched on writes and this plain won't work b) using a
driver on a machine with a different definition of 'int' say, and clobbering
two or more registers at the same time.

I've attached a couple of files to demonstrate what's going on - looking how
the C translates to x86 assembly is most instructive! (gcc -O2 -s testreg.c)

> Rick

Best Regards,
Alex (who's been hacking lots of C recently - Pup and xf86Wacom.c :)
-- 
Alex Butcher        Brainbench MVP for Internet Security: www.brainbench.com
Bristol, UK                        Need reliable and secure network systems?
PGP/GnuPG ID:0x271fd950                           <http://www.assursys.com/>
-------------- next part --------------
#include <linux/types.h>

struct regstruct
{
	u_int32_t 	registera;
	u_int8_t	registerb;
	u_int32_t	registerc;
} __attribute__ ((__packed__));

typedef struct regstruct* regptr;

void write(int reg)
{
	char *regbase=(char *)100000;
	
	int offset=4;
	
	*(regbase+offset)=(int)reg;
	
	return;
}

int read(void)
{
	char *regbase=(char *)100000;
	
	int offset=4;
	
	return((int)*(regbase+offset));
}

void writestruct(unsigned int rega, unsigned char regb, unsigned int regc)
{
	struct regstruct *registers=(struct regstruct *)200000;

	registers->registera=(unsigned int)rega;
	registers->registerb=(unsigned char)regb;
	registers->registerc=(unsigned int)regc;
	
	return;
}

unsigned char registerb(void)
{
	regptr registers=(regptr)300000;
	
	return(registers->registerb);
}
-------------- next part --------------
	.file	"testreg.c"
	.text
	.align 2
	.p2align 2,,3
.globl write
	.type	write, at function
write:
	pushl	%ebp
	movl	%esp, %ebp
	movl	8(%ebp), %eax
	movb	%al, 100004
	leave
	ret
.Lfe1:
	.size	write,.Lfe1-write
	.align 2
	.p2align 2,,3
.globl read
	.type	read, at function
read:
	pushl	%ebp
	movl	%esp, %ebp
	movsbl	100004,%eax
	leave
	ret
.Lfe2:
	.size	read,.Lfe2-read
	.align 2
	.p2align 2,,3
.globl writestruct
	.type	writestruct, at function
writestruct:
	pushl	%ebp
	movl	%esp, %ebp
	movl	12(%ebp), %eax
	movl	8(%ebp), %edx
	movl	%edx, 200000
	movb	%al, 200004
	movl	16(%ebp), %eax
	movl	%eax, 200005
	leave
	ret
.Lfe3:
	.size	writestruct,.Lfe3-writestruct
	.align 2
	.p2align 2,,3
.globl registerb
	.type	registerb, at function
registerb:
	pushl	%ebp
	movl	%esp, %ebp
	movzbl	300004, %eax
	leave
	ret
.Lfe4:
	.size	registerb,.Lfe4-registerb
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"


More information about the Sclug mailing list