19. System Dependencies

comp.lang.c FAQ list · Question 19.1

Q: How can I read a single character from the keyboard without waiting for the RETURN key? How can I stop characters from being echoed on the screen as they're typed?


A: Alas, there is no standard or portable way to do these things in C. Concepts such as screens and keyboards are not even mentioned in the Standard, which deals only with simple I/O ``streams'' of characters.

Input to a computer program typically passes through several stages. At the lowest level, device-dependent routines within the operating system handle the details of interfacing with particular devices such as keyboards, serial lines, disk drives, etc. Above that, modern operating systems tend to have a device-independent I/O layer, unifying access to any file or device. Finally, a C program is usually insulated from the operating system's I/O facilities by the portable functions of the stdio library.

At some level, interactive keyboard input is usually collected and presented to the requesting program a line at a time. This gives the operating system a chance to support input line editing (backspace/delete/rubout, etc.) in a consistent way, without requiring that it be built into every program. Only when the user is satisfied and presses the RETURN key (or equivalent) is the line made available to the calling program. Even if the calling program appears to be reading input a character at a time (with getchar or the like), the first call blocks until the user has typed an entire line, at which point potentially many characters become available and many character requests (e.g. getchar calls) are satisfied in quick succession.

When a program wants to read each character immediately as it arrives, its course of action will depend on where in the input stream the line collection is happening and how it can be disabled. Under some systems (e.g. MS-DOS, VMS in some modes), a program can use a different or modified set of OS-level input calls to bypass line-at-a-time input processing. Under other systems (e.g. Unix, VMS in other modes), the part of the operating system responsible for serial input (often called the ``terminal driver'') must be placed in a mode which turns off line-at-a-time processing, after which all calls to the usual input routines (e.g. read, getchar, etc.) will return characters immediately. Finally, a few systems (particularly older, batch-oriented mainframes) perform input processing in peripheral processors which cannot be told to do anything other than line-at-a-time input.

Therefore, when you need to do character-at-a-time input (or disable keyboard echo, which is an analogous problem), you will have to use a technique specific to the system you're using, assuming it provides one. Since comp.lang.c is oriented towards those topics that the C language has defined support for, you will usually get better answers to other questions by referring to a system-specific newsgroup such as comp.unix.questions or comp.os.msdos.programmer, and to the FAQ lists for these groups. Note that the answers may differ even across variants of otherwise similar systems (e.g. across different variants of Unix); bear in mind when answering system-specific questions that the answer that applies to your system may not apply to everyone else's.

However, since these questions are frequently asked here, here are brief answers for some common situations.

Depending on which operating system you're using and what libraries you have available, you may be able to use one (or more!) of the following techniques:

(As an aside, note that simply using setbuf or setvbuf to set stdin to unbuffered will not generally serve to allow character-at-a-time input.)

If you change terminal modes, save a copy the initial state and be sure to restore it no matter how your program terminates.

If you're trying to write a portable program, a good approach is to define your own suite of three functions to (1) set the terminal driver or input system into character-at-a-time mode (if necessary), (2) get characters, and (3) return the terminal driver to its initial state when the program is finished. (Ideally, such a set of functions might be part of the C Standard, some day.)

As an example, here is a tiny test program which prints the decimal values of the next ten characters as they are typed, without waiting for RETURN. It is written in terms of three functions, as described, and is followed by implementations of the three functions for curses, classic Unix, System V Unix, and MS-DOS. (The on-line archives associated with this list contain a more complete set of functions.)

#include <stdio.h>

main()
{
	int i;
	if(tty_break() != 0)
		return 1;
	for(i = 0; i < 10; i++)
		printf(" = %d\n", tty_getchar());
	tty_fix();
	return 0;
}

This implementation of the three functions is for curses:

#include <curses.h>

int tty_break()
{
	initscr();
	cbreak();
	return 0;
}

int tty_getchar()
{
	return getch();
}

int tty_fix()
{
	endwin();
	return 0;
}

Here is the code for ``classic'' (V7, BSD) Unix:

#include <stdio.h>
#include <sgtty.h>

static struct sgttyb savemodes;
static int havemodes = 0;

int tty_break()
{
	struct sgttyb modmodes;
	if(ioctl(fileno(stdin), TIOCGETP, &savemodes) < 0)
		return -1;
	havemodes = 1;
	modmodes = savemodes;
	modmodes.sg_flags |= CBREAK;
	return ioctl(fileno(stdin), TIOCSETN, &modmodes);
}

int tty_getchar()
{
	return getchar();
}

int tty_fix()
{
	if(!havemodes)
		return 0;
	return ioctl(fileno(stdin), TIOCSETN, &savemodes);
}

The code for System V Unix is similar:

#include <stdio.h>
#include <termio.h>

static struct termio savemodes;
static int havemodes = 0;

int tty_break()
{
	struct termio modmodes;
	if(ioctl(fileno(stdin), TCGETA, &savemodes) < 0)
		return -1;
	havemodes = 1;
	modmodes = savemodes;
	modmodes.c_lflag &= ~ICANON;
	modmodes.c_cc[VMIN] = 1;
	modmodes.c_cc[VTIME] = 0;
	return ioctl(fileno(stdin), TCSETAW, &modmodes);
}

int tty_getchar()
{
	return getchar();
}

int tty_fix()
{
	if(!havemodes)
		return 0;
	return ioctl(fileno(stdin), TCSETAW, &savemodes);
}

Finally, here is an implementation for MS-DOS:

int tty_break() { return 0; }

int tty_getchar()
{
	return getche();
}

int tty_fix() { return 0; }

Turning off echo is left as an exercise for the reader.

For detailed information on terminal (keyboard and screen) I/O programming, see an FAQ list, book, or documentation set specific to your operating system. (Note that there can be many more details to take care of, e.g. special characters to disable as well as more mode bits to toggle, than were mentioned above.)

See also question 19.2.

Additional links: more solutions

References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1
POSIX Sec. 7




comp.lang.c FAQ list · Question 19.2

Q: How can I find out if there are characters available for reading (and if so, how many)? Alternatively, how can I do a read that will not block if there are no characters available?


A: These, too, are entirely operating-system-specific. Some versions of curses have a nodelay function. Depending on your system, you may also be able to use ``nonblocking I/O'', or a system call named select or poll, or the FIONREAD ioctl, or c_cc[VTIME], or kbhit, or rdchk, or the O_NDELAY option to open or fcntl. You can also try setting an alarm to cause a blocking read to time out after a certain interval (under Unix, look at alarm, signal, and maybe setitimer).

If what you're trying to do is read input from several sources without blocking, you will definitely want to use some kind of a ``select'' call, because a busy-wait, polling loop is terribly inefficient on a multitasking system.

See also question 19.1.




comp.lang.c FAQ list · Question 19.3

Q: How can I display a percentage-done indication that updates itself in place, or show one of those ``twirling baton'' progress indicators?


A: These simple things, at least, you can do fairly portably. Printing the character '\r' will usually give you a carriage return without a line feed, so that you can overwrite the current line. The character '\b' is a backspace, and will usually move the cursor one position to the left.

Using these characters, you can print a percentage-done indicator:

	for(i = 0; i < lotsa; i++) {
		printf("\r%3d%%", (int)(100L * i / lotsa));
		fflush(stdout);
		do_timeconsuming_work();
	}
	printf("\ndone.\n");
or a baton:
	printf("working: ");
	for(i = 0; i < lotsa; i++) {
		printf("%c\b", "|/-\\"[i%4]);
		fflush(stdout);
		do_timeconsuming_work();
	}
	printf("done.\n");

See also question 12.4.

References: ISO Sec. 5.2.2




comp.lang.c FAQ list · Question 19.4

Q: How can I clear the screen?
How can I print text in color?
How can I move the cursor to a specific x, y position?


A: Such things depend on the terminal type (or display) you're using. You will have to use a library such as termcap, terminfo, or curses, or some system-specific routines, to perform these operations.

Functions in the curses library to look for are clear, move, standout/standend, and attron/attroff/attrset; the last three work with attribute codes such as A_REVERSE. In MS-DOS libraries, there are typically functions named gotoxy and clrscr or _clearscreen; you can also use the ANSI.SYS driver or low-level interrupts. Under termcap or terminfo, use tgetstr to retrieve strings like cl, so/se, and cm for clear screen, standout mode, and cursor motion respectively, then output the strings; using cm additionally requires calling tgoto. Some baroque terminals require attention to other ``capabilities'' as well; study the documentation carefully. Be aware that some older terminals may not support the desired capabilities at all.

Most modern terminal emulation schemes support the ANSI escape sequences for cursor motion and visual attributes, so if you're willing to sacrifice portability, you can print those sequences directly. Here is a tiny example to whet your appetite:

printf("\033[2J");		/* clear screen */
printf("\033[%d;%dH", 10, 20);	/* move cursor (row 10, col 20) */
printf("Hello, ");
printf("\033[7mworld\033[0m!");	/* inverse video */
Here is a link to some more explanation, and brief lists of codes. The portable way of emitting these sequences (if you're not going whole-hog and using curses) is to use termcap or terminfo; here is an example.

For clearing the screen, a halfway portable solution is to print a form-feed character ('\f'), which will cause some displays to clear. Even more portable (albeit even more gunky) might be to print enough newlines to scroll everything away (although of course this leaves the cursor at the bottom of the screen, not the top). As a last resort, you could use system (see question 19.27) to invoke an operating system clear-screen command.

References: PCS Sec. 5.1.4 pp. 54-60, Sec. 5.1.5 pp. 60-62
Strang, Programming with curses
Strang, Mui, and O'Reilly, termcap & terminfo




comp.lang.c FAQ list · Question 19.4b

Q: I'm compiling some test programs on a windows-based system, and the windows containing my program's output are closing so quickly after my program calls exit that I can't see the output. How can I make it pause before closing?


A: After wondering why the author of your compiler's run-time system didn't take care of this for you, simply add the lines

	printf("Hit RETURN to exit"\n");
	fflush(stdout);
	(void)getchar();
just before the end of your program. (If you want to wait for any keystroke, not just the RETURN key, see question 19.1.)


comp.lang.c FAQ list · Question 19.5

Q: How do I read the arrow keys? What about function keys?


A: Terminfo, some versions of termcap, and some versions of curses have support for these non-ASCII keys. Typically, a special key sends a multicharacter sequence (usually beginning with ESC, '\033'); parsing these can be tricky. (curses will do the parsing for you, if you call keypad first.)

Under MS-DOS, if you receive a character with value 0 (not '0'!) while reading the keyboard, it's a flag indicating that the next character read will be a code indicating a special key. See any DOS programming guide for lists of keyboard scan codes. (Very briefly: the up, left, right, and down arrow keys are 72, 75, 77, and 80, and the function keys are 59 through 68.)

References: PCS Sec. 5.1.4 pp. 56-7




comp.lang.c FAQ list · Question 19.6

Q: How do I read the mouse?


A: Consult your system documentation, or ask on an appropriate system-specific newsgroup (but check its FAQ list first). Mouse handling is completely different under the X window system, MS-DOS, the Macintosh, and probably every other system.

References: PCS Sec. 5.5 pp. 78-80




comp.lang.c FAQ list · Question 19.7

Q: How can I do serial (``comm'') port I/O?


A: It's system-dependent. Under Unix, you typically open, read, and write a device file in /dev, and use the facilities of the terminal driver to adjust its characteristics. (See also questions 19.1 and 19.2.) Under MS-DOS, you can use the predefined stream stdaux, or a special file like COM1, or some primitive BIOS interrupts, or (if you require decent performance) any number of interrupt-driven serial I/O packages. Several netters recommend the book C Programmer's Guide to Serial Communications, by Joe Campbell.




comp.lang.c FAQ list · Question 19.8

Q: How can I direct output to the printer?


A: Under Unix, either use popen (see question 19.30) to write to the lp or lpr program, or perhaps open a special file like /dev/lp. Under MS-DOS, write to the (nonstandard) predefined stdio stream stdprn, or open the special files PRN or LPT1. Under some circumstances, another (and perhaps the only) possibility is to use a window manager's screen-capture function, and print the resulting bitmap.

References: PCS Sec. 5.3 pp. 72-74




comp.lang.c FAQ list · Question 19.9

Q: How do I send escape sequences to control a terminal or other device?


A: If you can figure out how to send characters to the device at all (see question 19.8), it's easy enough to send escape sequences. In ASCII, the ESC code is 033 (27 decimal), so code like

	fprintf(ofd, "\033[J");
sends the sequence ESC [ J .

Some programmers prefer to parameterize the ESC code, like this:

	#define ESC 033

	fprintf(ofd, "%c[J", ESC);



comp.lang.c FAQ list · Question 19.9b

Q: How can I access an I/O board directly?


A: At one level, at least, it's quite simple: you have a device register which is actually wired up so that the bits written to it get coverted to actual voltage levels in the real world that you can do interesting things with. In general, there are two ways to get the bits in and out. (A particular I/O board will use one method or the other; you'll need to consult its documentation for details.)

  1. If the device is accessed via a dedicated ``I/O port'', use system-specific functions to communicate with it. Under MS-DOS, for example, there were quasistandard ``inport'' and ``outport'' instructions.
  2. If the device uses ``memory-mapped I/O'', that is, if the device register(s) are accessed as if they were normal memory at particular, known locations within the processor's addressing space, use contrived pointer variables to access those locations. See question 19.25.


    comp.lang.c FAQ list · Question 19.10

    Q: How can I do graphics?


    A: Once upon a time, Unix had a fairly nice little set of device-independent plot functions described in plot(3) and plot(5). The GNU libplot library, written by Robert Maier, maintains the same spirit and supports many modern plot devices; see http://www.gnu.org/software/plotutils/plotutils.html.

    A modern, platform-independent graphics library (which also supports 3D graphics and animation) is OpenGL. Other graphics standards which may be of interest are GKS and PHIGS.

    If you're programming for MS-DOS, you'll probably want to use libraries conforming to the VESA or BGI standards.

    If you're trying to talk to a particular plotter, making it draw is usually a matter of sending it the appropriate escape sequences; see also question 19.9. The vendor may supply a C-callable library, or you may be able to find one on the net.

    If you're programming for a particular window system (Macintosh, X windows, Microsoft Windows), you will use its facilities; see the relevant documentation or newsgroup or FAQ list.

    References: PCS Sec. 5.4 pp. 75-77




    comp.lang.c FAQ list · Question 19.10b

    Q: How can I display GIF and JPEG images?


    A: It will depend on your display environment, which may already provide these functions. Reference JPEG software is at http://www.ijg.org/files/.




    comp.lang.c FAQ list · Question 19.10c

    Q: How can I load new fonts for display?


    A: It's system-dependent.




    comp.lang.c FAQ list · Question 19.10d

    Q: How can I send mail from within a C program?


    A: Under Unix, open a pipe to the mail program, or perhaps /usr/lib/sendmail. See question 19.30.




    comp.lang.c FAQ list · Question 19.11

    Q: How can I check whether a file exists? I want to warn the user if a requested input file is missing.


    A: It's surprisingly difficult to make this determination reliably and portably. Any test you make can be invalidated if the file is created or deleted (i.e. by some other process) between the time you make the test and the time you try to open the file.

    Three possible test functions are stat, access, and fopen. (To make an approximate test using fopen, just open for reading and close immediately, although failure does not necessarily indicate nonexistence.) Of these, only fopen is widely portable, and access, where it exists, must be used carefully if the program uses the Unix set-UID feature. (If you have the choice, the best compromise is probably one of the stat functions.)

    Rather than trying to predict in advance whether an operation such as opening a file will succeed, it's often better to try it, check the return value, and complain if it fails. (Obviously, this approach won't work if you're trying to avoid overwriting an existing file, unless you've got something like the O_EXCL file opening option available, which does just what you want in this case.)

    References: PCS Sec. 12 pp. 189,213
    POSIX Sec. 5.3.1, Sec. 5.6.2, Sec. 5.6.3




    comp.lang.c FAQ list · Question 19.12

    Q: How can I find out the size of a file, prior to reading it in?


    A: If the ``size of a file'' is the number of characters you'll be able to read from it in C (or which were written to it by a previous program), it can be difficult or impossible to determine this number exactly (other than by reading the whole file).

    Under Unix, the stat call (specifically, the st_size field of the stat structure) will give you an exact answer. [footnote] Several other systems supply a Unix-like stat call, but the sizes reported for text files may be approximate (due to differing end-of-line representations; see question 12.40). You can open the file and use fstat, or fseek to the end of the file and then use ftell, but these tend to have the same problems: fstat is not portable, and generally tells you the same thing stat tells you; ftell is not guaranteed to return a byte count except for binary files (but, strictly speaking, binary files don't necessarily support fseek to SEEK_END at all). Some systems provide functions called filesize or filelength, but these are obviously not portable, either.

    Are you sure you have to determine the file's size in advance? Since the most accurate way of determining the size of a file as a C program will see it is to open the file and read it, perhaps you can rearrange the code to learn the size as it reads. (In general, your program should behave gracefully if the number of characters actually read does not match prior expectations, since any advance determination of the size might be approximate.) See also questions 7.29, 7.30, and 20.2.

    Additional links: further reading

    References: ISO Sec. 7.9.9.4
    H&S Sec. 15.5.1
    PCS Sec. 12 p. 213
    POSIX Sec. 5.6.2




    comp.lang.c FAQ list · Question 19.12b

    Q: How can I find the modification date and time of a file?


    A: The Unix and POSIX function is stat, which several other systems supply as well. (See also question 19.12.)




    comp.lang.c FAQ list · Question 19.13

    Q: How can a file be shortened in-place without completely clearing or rewriting it?


    A: BSD systems provide ftruncate, several others supply chsize, and a few may provide a (possibly undocumented) fcntl option F_FREESP. Under MS-DOS, you can sometimes use write(fd, "", 0). However, there is no portable solution, nor a way to delete blocks at the beginning or in the middle. See also question 19.14.




    comp.lang.c FAQ list · Question 19.14

    Q: How can I insert or delete a line (or record) in the middle of a file?


    A: In general, there is no way to do this. [footnote] The usual solution is simply to rewrite the file.

    When you find yourself needing to insert data into an existing file, here are a few alternatives you can try:

    Instead of actually deleting records, you might consider just marking them as deleted, and having the code which reads the file ignore them. (You could run a separate coalescion program once in a while to rewrite the file, finally discarding the deleted records. Or, if the records are all the same length, you could take the last record and use it to overwrite the record to be deleted, then truncate the file.)

    See also questions 12.30 and 19.13.

    Additional links: further reading




    comp.lang.c FAQ list · Question 19.15

    Q: How can I recover the file name given an open stream or file descriptor?


    A: This problem is, in general, insoluble. Under Unix, for instance, a scan of the entire disk (perhaps involving special permissions) would theoretically be required, and would fail if the descriptor were connected to a pipe or referred to a deleted file (and could give a misleading answer for a file with multiple links). It is best to remember the names of files yourself as you open them (perhaps with a wrapper function around fopen).




    comp.lang.c FAQ list · Question 19.16

    Q: How can I delete a file?


    A: The Standard C Library function is remove. (This is therefore one of the few questions in this section for which the answer is not ``It's system-dependent.'') On older, pre-ANSI Unix systems, remove may not exist, in which case you can try unlink. [footnote]

    References: K&R2 Sec. B1.1 p. 242
    ISO Sec. 7.9.4.1
    H&S Sec. 15.15 p. 382
    PCS Sec. 12 pp. 208,220-221
    POSIX Sec. 5.5.1, Sec. 8.2.4




    comp.lang.c FAQ list · Question 19.16b

    Q: How do I copy files?


    A: Either use system() to invoke your operating system's copy utility (see question 19.27), or open the source and destination files (using fopen or some lower-level file-opening system call), read characters or blocks of characters from the source file, and write them to the destination file. Here is a simple example:

    #include <stdio.h>
    
    int copyfile(char *fromfile, char *tofile)
    {
    	FILE *ifp, *ofp;
    	int c;
    
    	if((ifp = fopen(fromfile, "r")) == NULL) return -1;
    	if((ofp = fopen(tofile, "w")) == NULL) { fclose(ifp); return -1; }
    
    	while((c = getc(ifp)) != EOF)
    		putc(c, ofp);
    
    	fclose(ifp);
    	fclose(ofp);
    
    	return 0;
    }
    
    To copy a block at a time, rewrite the inner loop as
    	while((r = fread(buf, 1, sizeof(buf), ifp)) > 0)
    		fwrite(buf, 1, r, ofp);
    
    where r is an int and buf is a suitably-sized array of char.

    References: K&R Sec. 1, Sec. 7




    comp.lang.c FAQ list · Question 19.17

    Q: Why can't I open a file by its explicit path? The call

    fopen("c:\newdir\file.dat", "r")
    is failing.


    A: The file you actually requested--with the characters \n and \f in its name--probably doesn't exist, and isn't what you thought you were trying to open.

    In character constants and string literals, the backslash \ is an escape character, giving special meaning to the character following it. In order for literal backslashes in a pathname to be passed through to fopen (or any other function) correctly, they have to be doubled, so that the first backslash in each pair quotes the second one:

    	fopen("c:\\newdir\\file.dat", "r")
    
    Alternatively, under MS-DOS, it turns out that forward slashes are also accepted as directory separators, so you could use
    	fopen("c:/newdir/file.dat", "r")
    
    (Note, by the way, that header file names mentioned in preprocessor #include directives are not string literals, so you may not have to worry about backslashes there.)


    comp.lang.c FAQ list · Question 19.17b

    Q: fopen isn't letting me open files like "$HOME/.profile" and "~/.myrcfile".


    A: Under Unix, at least, environment variables like $HOME, along with the home-directory notation involving the ~ character, are expanded by the shell, and there's no mechanism to perform these expansions automatically when you call fopen.




    comp.lang.c FAQ list · Question 19.17c

    Q: How can I suppress the dreaded MS-DOS ``Abort, Retry, Ignore?'' message?


    A: Among other things, you need to intercept the DOS Critical Error Interrupt, interrupt 24H. See the comp.os.msdos.programmer FAQ list for more details.




    comp.lang.c FAQ list · Question 19.18

    Q: I'm getting an error, ``Too many open files''. How can I increase the allowable number of simultaneously open files?


    A: There are typically at least two resource limitations on the number of simultaneously open files: the number of low-level ``file descriptors'' or ``file handles'' available in the operating system, and the number of FILE structures available in the stdio library. Both must be sufficient. Under MS-DOS systems, you can control the number of operating system file handles with a line in CONFIG.SYS. Some compilers come with instructions (and perhaps a source file or two) for increasing the number of stdio FILE structures.

    Additional links: further reading




    comp.lang.c FAQ list · Question 19.19

    Q: How can I find out how much free space is available on disk?


    A: There is no portable way. Under some versions of Unix you can call statfs. Under MS-DOS, use interrupt 0x21 subfunction 0x36, or perhaps a routine such as diskfree. Another possibility is to use popen (see question 19.30) to invoke and read the output of a ``disk free'' command (df on Unix).

    (Note that the amount of free space apparently available on a disk may not match the size of the largest file you can store, for all sorts of reasons.)




    comp.lang.c FAQ list · Question 19.20

    Q: How can I read a directory in a C program?


    A: See if you can use the opendir and readdir functions, which are part of the POSIX standard and are available on most Unix variants. Implementations also exist for MS-DOS, VMS, and other systems. (MS-DOS also has FINDFIRST and FINDNEXT routines which do essentially the same thing, and MS Windows has FindFirstFile and FindNextFile.) readdir returns just the file names; if you need more information about the file, try calling stat. To match filenames to some wildcard pattern, see question 13.7.

    Here is a tiny example which lists the files in the current directory:

    #include <stdio.h>
    #include <sys/types.h>
    #include <dirent.h>
    
    main()
    {
    	struct dirent *dp;
    	DIR *dfd = opendir(".");
    	if(dfd != NULL) {
    		while((dp = readdir(dfd)) != NULL)
    			printf("%s\n", dp->d_name);
    		closedir(dfd);
    	}
    	return 0;
    }
    
    (On older systems, the header file to #include may be <direct.h> or <dir.h>, and the pointer returned by readdir may be a struct direct *. This example assumes that "." is a synonym for the current directory.)

    In a pinch, you could use popen (see question 19.30) to call an operating system list-directory program, and read its output. (If you only need the filenames displayed to the user, you could conceivably use system; see question 19.27.)

    References: K&R2 Sec. 8.6 pp. 179-184
    PCS Sec. 13 pp. 230-1
    POSIX Sec. 5.1
    Schumacher, ed., Software Solutions in C Sec. 8




    comp.lang.c FAQ list · Question 19.21

    Q: How do I create a directory?
    How do I remove a directory (and its contents)?


    A: If your operating system supports these services, they are likely to be provided in C via functions named mkdir and rmdir. Removing a directory's contents as well will require listing them (see question 19.20) and calling remove (see also question 19.16). If you don't have these C functions available, try system (see question 19.27) along with your operating system's delete command(s).

    References: PCS Sec. 12 pp. 203-4
    POSIX Secs. 5.4.1,5.5.2




    comp.lang.c FAQ list · Question 19.22

    Q: How can I find out how much memory is available?


    A: Your operating system may provide a routine which returns this information, but it's quite system-dependent. (Also, the number may vary over time.) If you're trying to predict whether you'll be able to allocate a certain amount of memory, just try it--call malloc (requesting that amount) and check the return value.




    comp.lang.c FAQ list · Question 19.23

    Q: How can I allocate arrays or structures bigger than 64K?


    A: A reasonable computer ought to give you transparent access to all available memory. If you're not so lucky, you'll either have to rethink your program's use of memory, or use various system-specific techniques.

    64K is (still) a pretty big chunk of memory. No matter how much memory your computer has available, it's asking a lot to be able to allocate huge amounts of it contiguously. (The C Standard does not guarantee that single objects can be 32K or larger, or 64K for C99.) Often it's a good idea to use data structures which don't require that all memory be contiguous. For dynamically-allocated multidimensional arrays, you can use pointers to pointers, as illustrated in questions 6.16 and 20.2. Instead of a large array of structures, you can use a linked list, or an array of pointers to structures.

    If you're using a PC-compatible (8086-based) system, and running up against a 64K or 640K limit, consider using ``huge'' memory model, or expanded or extended memory, or malloc variants such as halloc or farmalloc, or a 32-bit ``flat'' compiler (e.g. djgpp, see question 18.3), or some kind of a DOS extender, or another operating system.

    References: ISO Sec. 5.2.4.1
    C9X Sec. 5.2.4.1




    comp.lang.c FAQ list · Question 19.24

    Q: What does the error message ``DGROUP data allocation exceeds 64K'' mean, and what can I do about it? I thought that using large model meant that I could use more than 64K of data!


    A: Even in large memory models, MS-DOS compilers apparently toss certain data (strings, some initialized global or static variables) into a default data segment, and it's this segment that is overflowing. Either use less global data, or, if you're already limiting yourself to reasonable amounts (and if the problem is due to something like the number of strings), you may be able to coax the compiler into not using the default data segment for so much. Some compilers place only ``small'' data objects in the default data segment, and give you a way (e.g. the /Gt option under Microsoft compilers) to configure the threshold for ``small.''




    comp.lang.c FAQ list · Question 19.25

    Q: How can I access memory (a memory-mapped device, or graphics memory) located at a certain address?
    How can I do PEEK and POKE in C?


    A: Set a pointer, of the appropriate type, to the right number (using an explicit cast to assure the compiler that you really do intend this nonportable conversion):

    	unsigned int *magicloc = (unsigned int *)0x12345678;
    
    Then, *magicloc refers to the location you want. [footnote] If the location is a memory-mapped I/O register, you will probably also want to use the volatile qualifier: ``volatile unsigned int *magicloc''. (If you want to refer to a byte at a certain address rather than a word, use unsigned char *.)

    Under MS-DOS, you may find a macro like MK_FP() handy for working with segments and offsets. As suggested by Gary Blaine, you can also declare tricky array pointers which allow you to access screen memory using array notation. For example, on an MS-DOS machine in an 80x25 text mode, given the declaration

    unsigned short (far * videomem)[80] =
    		(unsigned short (far *)[80])0xb8000000;
    
    you can access the character and attribute byte at row i, column j with videomem[i][j].

    Many operating systems execute user-mode programs in a protected mode where direct access to I/O devices (or to any address outside the running process) is simply not possible. In such cases you will have to ask the operating system to carry out I/O operations for you.

    See also questions 4.14 and 5.19.

    References: K&R1 Sec. A14.4 p. 210
    K&R2 Sec. A6.6 p. 199
    ISO Sec. 6.3.4
    Rationale Sec. 3.3.4
    H&S Sec. 6.2.7 pp. 171-2




    comp.lang.c FAQ list · Question 19.25b

    Q: How can I determine whether a machine's byte order is big-endian or little-endian?


    A: See question 20.9.




    comp.lang.c FAQ list · Question 19.26

    Q: How can I access an interrupt vector located at the machine's location 0? If I set a pointer to 0, the compiler might translate it to some nonzero internal null pointer value.


    A: See question 5.19.




    comp.lang.c FAQ list · Question 19.27

    Q: How can I invoke another program (a standalone executable, or an operating system command) from within a C program?


    A: Use the library function system, which does exactly that.

    Some systems also provide a family of spawn routines which accomplish approximately the same thing. system is more ``portable'' in that it is required under the ANSI C Standard, although the interpretation of the command string--its syntax and the set of commands accepted--will obviously vary tremendously.

    The system function ``calls'' a command in the manner of a subroutine, and control eventually returns to the calling program. If you want to overlay the calling program with another program (that is, a ``chain'' operation) you'll need a system-specific routine, such as the exec family on Unix.

    Note that system's return value is at best the command's exit status (although even that is not guaranteed), and usually has nothing to do with the output of the command.

    See also questions 19.28 and 19.30.

    References: K&R1 Sec. 7.9 p. 157
    K&R2 Sec. 7.8.4 p. 167, Sec. B6 p. 253
    ISO Sec. 7.10.4.5
    H&S Sec. 19.2 p. 407
    PCS Sec. 11 p. 179




    comp.lang.c FAQ list · Question 19.28

    Q: How can I call system when parameters (filenames, etc.) of the executed command aren't known until run time?


    A: Just use sprintf (or perhaps strcpy and strcat) to build the command string in a buffer, then call system with that buffer. (Make sure the buffer is allocated with enough space; see also questions 7.2 and 12.21.)

    Here is a contrived example suggesting how you might build a data file, then sort it (assuming the existence of a sort utility, and Unix- or MS-DOS-style input/output redirection):

    	char *datafile = "file.dat";
    	char *sortedfile = "file.sort";
    	char cmdbuf[50];
    	FILE *fp = fopen(datafile, "w");
    
    	/* ...write to fp to build data file... */
    
    	fclose(fp);
    
    	sprintf(cmdbuf, "sort < %s > %s", datafile, sortedfile);
    	system(cmdbuf);
    
    	fp = fopen(sortedfile, "r");
    	/* ...now read sorted data from fp... */
    

    See also question 12.28b.




    comp.lang.c FAQ list · Question 19.29

    Q: How do I get an accurate error status return from system on MS-DOS?


    A: You can't; COMMAND.COM doesn't tend to provide one. If you don't need COMMAND.COM's services (i.e. if you're just trying to invoke a simple program, without I/O redirection and such) try one of the spawn routines, instead.




    comp.lang.c FAQ list · Question 19.30

    Q: How can I invoke another program or command and trap its output?


    A: Unix and some other systems provide a popen function, which sets up a stdio stream on a pipe connected to the process running a command, so that the calling program can read the output (or alternatively supply the input). Using popen, the last example from question 19.28 would look like

    	extern FILE *popen();
    
    	sprintf(cmdbuf, "sort < %s", datafile);
    
    	fp = popen(cmdbuf, "r");
    
    	/* ...now read sorted data from fp... */
    
    	pclose(fp);
    
    (Do be sure to call pclose, as shown; leaving it out will seem to work at first but may eventually run you out of processes or file descriptors.)

    If you can't use popen, you may be able to use system, with the output going to a file which you then open and read, as the code in question 19.28 was doing already. [footnote]

    If you're using Unix and popen isn't sufficient, you can learn about pipe, dup, fork, and exec.

    (One thing that probably would not work, by the way, would be to use freopen.)

    References: PCS Sec. 11 p. 169




    comp.lang.c FAQ list · Question 19.31

    Q: How can my program discover the complete pathname to the executable from which it was invoked?


    A: argv[0] may contain all or part of the pathname, or it may contain nothing. You may be able to duplicate the command language interpreter's search path logic to locate the executable if the name in argv[0] is present but incomplete. However, there is no guaranteed solution.

    References: K&R1 Sec. 5.11 p. 111
    K&R2 Sec. 5.10 p. 115
    ISO Sec. 5.1.2.2.1
    H&S Sec. 20.1 p. 416




    comp.lang.c FAQ list · Question 19.32

    Q: How can I automatically locate a program's configuration files in the same directory as the executable?


    A: It's hard, in general; it's an equivalent problem to the one in question 19.31. Even if you can figure out a workable way to do it, you might want to consider making the program's auxiliary (library) directory configurable, perhaps with an environment variable. (It's especially important to allow variable placement of a program's configuration files when the program will be used by several people, e.g. on a multiuser system.)




    comp.lang.c FAQ list · Question 19.33

    Q: How can a process change an environment variable in its caller?


    A: It may or may not be possible to do so at all. Different operating systems implement global name/value functionality similar to the Unix environment in different ways. Whether the ``environment'' can be usefully altered by a running program, and if so, how, is system-dependent.

    Under Unix, a process can modify its own environment (some systems provide setenv or putenv functions for the purpose), and the modified environment is generally passed on to child processes, but it is not propagated back to the parent process. (The environment of the parent process can only be altered if the parent is explicitly set up to listen for some kind of change requests. The conventional execution of the BSD ``tset'' program in .profile and .login files effects such a scheme.) Under MS-DOS, it's possible to manipulate the master copy of the environment, but the required techniques are arcane. (See an MS-DOS FAQ list.)




    comp.lang.c FAQ list · Question 19.34

    Q: How can I open files mentioned on the command line, and parse option flags?


    A: See question 20.3.




    comp.lang.c FAQ list · Question 19.35

    Q: Is exit(status) truly equivalent to returning the same status from main?


    A: See question 11.16.




    comp.lang.c FAQ list · Question 19.36

    Q: How can I read in an object file and jump to locations in it?


    A: You want a dynamic linker or loader. It may be possible to malloc some space and read in object files, but you have to know an awful lot about object file formats, relocation, etc., and this approach can't work if code and data reside in separate address spaces or if code is otherwise privileged.

    Under BSD Unix, you could use system and ld -A to do the linking for you. Many versions of SunOS and System V have the -ldl library containing routines like dlopen and dlsym which allow object files to be dynamically loaded. Under VMS, use LIB$FIND_IMAGE_SYMBOL. GNU has a package called ``dld''. See also question 15.13.




    comp.lang.c FAQ list · Question 19.37

    Q: How can I implement a delay, or time a user's response, with sub-second resolution?


    A: Unfortunately, there is no portable way. Routines you might look for on your system include clock, delay, ftime, gettimeofday, msleep, nap, napms, nanosleep, setitimer, sleep, Sleep, times, and usleep. (A function called wait, however, is at least under Unix not what you want.) The select and poll calls (if available) can be pressed into service to implement simple delays. On MS-DOS machines, it is possible to reprogram the system timer and timer interrupts.

    Of these, only clock is part of the ANSI Standard. The difference between two calls to clock gives elapsed execution time, and may even have subsecond resolution, if CLOCKS_PER_SEC is greater than 1. However, clock gives elapsed processor time used by the current program, which on a multitasking system (or in a non-CPU-intensive program) may differ considerably from real time.

    If you're trying to implement a delay and all you have available is a time-reporting function, you can implement a CPU-intensive busy-wait, but this is only an option on a single-user, single-tasking machine, as it is terribly antisocial to any other processes. Under a multitasking operating system, be sure to use a call which puts your process to sleep for the duration, such as sleep or select, or pause in conjunction with alarm or setitimer.

    For really brief delays, it's tempting to use a do-nothing loop like

    	long int i;
    	for(i = 0; i < 1000000; i++)
    		;
    
    but resist this temptation if at all possible! For one thing, your carefully-calculated delay loops will stop working properly next month when a faster processor comes out. Perhaps worse, a clever compiler may notice that the loop does nothing and optimize it away completely.

    Additional links: A technique involving I/O instructions described by Pedro Zorzenon Neto

    References: H&S Sec. 18.1 pp. 398-9
    PCS Sec. 12 pp. 197-8,215-6
    POSIX Sec. 4.5.2




    comp.lang.c FAQ list · Question 19.38

    Q: How can I trap or ignore keyboard interrupts like control-C?


    A: The basic step is to call signal, either as

    	#include <signal.h>
    	signal(SIGINT, SIG_IGN);
    
    to ignore the interrupt signal, or as
    	extern void func(int);
    	signal(SIGINT, func);
    
    to cause control to transfer to function func on receipt of an interrupt signal. [footnote]

    On a multi-tasking system such as Unix, it's best to use a slightly more involved technique:

    	extern void func(int);
    	if(signal(SIGINT, SIG_IGN) != SIG_IGN)
    		signal(SIGINT, func);
    
    The test and extra call ensure that a keyboard interrupt typed in the foreground won't inadvertently interrupt a program running in the background (and it doesn't hurt to code calls to signal this way on any system). [footnote]

    On some systems, keyboard interrupt handling is also a function of the mode of the terminal-input subsystem; see question 19.1. On some systems, checking for keyboard interrupts is only performed when the program is reading input, and keyboard interrupt handling may therefore depend on which input routines are being called (and whether any input routines are active at all). On MS-DOS systems, setcbrk or ctrlbrk functions may also be involved.

    References: ISO Secs. 7.7,7.7.1
    H&S Sec. 19.6 pp. 411-3
    PCS Sec. 12 pp. 210-2
    POSIX Secs. 3.3.1,3.3.4




    comp.lang.c FAQ list · Question 19.39

    Q: How can I handle floating-point exceptions gracefully?


    A: On many systems, you can define a function matherr which will be called when there are certain floating-point errors, such as errors in the math routines in <math.h>. You may also be able to use signal (see question 19.38) to catch SIGFPE. See also questions 14.9 and 20.6b.

    References: Rationale Sec. 4.5.1




    comp.lang.c FAQ list · Question 19.39b

    Q: How can I ensure that integer arithmetic doesn't overflow?


    A: See question 20.6b.




    comp.lang.c FAQ list · Question 19.40

    Q: How do I... Use sockets? Do networking? Write client/server applications?


    A: All of these questions are outside of the scope of this list and have much more to do with the networking facilities which you have available than they do with C. Good books on the subject are Douglas Comer's three-volume Internetworking with TCP/IP and W. R. Stevens's UNIX Network Programming. There is also plenty of information out on the net itself, including the ``Unix Socket FAQ'', and "Beej's Guide to Network Programming".

    (One tip: depending on your OS, you may need to explicitly request the -lsocket and -lnsl libraries; see question 13.25.)




    comp.lang.c FAQ list · Question 19.40a

    Q: Can I combine .OBJ and .LIB files from Microsoft C and Turbo C?


    A: Not easily; see the comp.os.msdos.programmer FAQ list.




    comp.lang.c FAQ list · Question 19.40b

    Q: How do I... Use BIOS calls? Write ISR's? Create TSR's?


    A: These are very particular to specific systems (PC compatibles running MS-DOS, most likely). You'll get much better information in a specific newsgroup such as comp.os.msdos.programmer or its FAQ list; another excellent resource is Ralf Brown's interrupt list.




    comp.lang.c FAQ list · Question 19.40c

    Q: I'm trying to compile this program, but the compiler is complaining that ``union REGS'' is undefined, and the linker is complaining that int86 is undefined.


    A: Those have to do with MS-DOS interrupt programming. They don't exist on other systems.




    comp.lang.c FAQ list · Question 19.40d

    Q: What are ``near'' and ``far'' pointers?


    A: These days, they're pretty much obsolete; they're definitely system-specific. They had to do with 16-bit programming under MS-DOS and perhaps some early versions of Windows. If you really need to know, see a DOS- or Windows-specific programming reference. If you're using a machine which doesn't require (or permit) making the near/far pointer distinction, just delete the unnecessary ``near'' and ``far'' keywords (perhaps using the preprocessor: ``#define far /* nothing */'').




    comp.lang.c FAQ list · Question 19.41

    Q: But I can't use all these nonstandard, system-dependent functions, because my program has to be ANSI compatible!


    A: You're out of luck. Either you misunderstood your requirement, or it's an impossible one to meet. ANSI/ISO Standard C simply does not define ways of doing these things; it is a language standard, not an operating system standard. An international standard which does address many of these issues is POSIX (IEEE 1003.1, ISO/IEC 9945-1), and many operating systems (not just Unix) now have POSIX-compatible programming interfaces.

    It is possible, and desirable, for most of a program to be ANSI-compatible, deferring the system-dependent functionality to a few routines in a few files which are either heavily #ifdeffed or rewritten entirely for each system ported to; see question 19.1 for an example. See also question 19.42.




    comp.lang.c FAQ list · Question 19.42

    Q: Why isn't any of this standardized in C? Any real program has to do some of these things.


    A: Actually, some standardization has occurred along the way. In the beginning, C did not have a standard library at all; programmers always had to ``roll their own'' utility routines. After several abortive attempts, a certain set of library routines (including the str* and stdio families of routines) became a de facto standard, at least on Unix systems, but the library was not yet a formal part of the language. Vendors could (and occasionally did) provide completely different routines along with their compilers.

    In ANSI/ISO Standard C, a library definition (based on the 1984 /usr/group standard, and largely compatible with the traditional Unix library) was adopted with as much standing as the language itself. The Standard C library's treatment of file and device I/O is, however, rather minimal. It states how streams of characters are written to and read from files, and it provides a few suggestions about the display behavior of control characters like \b, \r, and \t, but beyond that it is silent. (Many of these issues are, however, addressed and standardized in Posix.)

    If the Standard were to attempt to define standard mechanisms for accessing things like keyboards and displays, it might seem to be a big convenience for programmers. But it would be a monumental task: there is already a huge variety of display devices, and huge variation among the operating systems through which they are usually accessed. We cannot assume that the years to come will offer any less variety.

    At one time the common output device for C programs was a Teletype; later it was a ``dumb'' terminal, after that it was a ``smart'' VT100 or other ANSI X3.64-compatible terminal which today might be called ``dumb.'' Today it's likely to be a bitmapped color display screen. What will it be in five years? How will the operating systems of that time deal with its capabilities?

    See also question 11.34.

    References: Rationale Sec. 2.2.2, Sec. 4.9, Sec. 4.9.2





    Read sequentially: prev next up



    about this FAQ list   about eskimo   search   feedback   copyright

    Hosted by Eskimo North