Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: Pragmas Message-ID: <504@cresswell.quintus.UUCP> Date: 3 Jan 88 04:54:05 GMT References: <8801021358.AA15890@decwrl.dec.com> Organization: Quintus Computer Systems, Mountain View, CA Lines: 109 Summary: #pragma is wrong place In article <8801021358.AA15890@decwrl.dec.com>, minow@thundr.dec.com (Martin Minow THUNDR::MINOW ML3-5/U26 223-9922) gives some examples of #pragmas. (1) > (program sections) -- this let you write data into specific areas > that were resolved to absolute base addresses by the linker. (2) declaring variables to be device registers > #pragma device_register foo, bar; (3) > On ... the 80x86 family ... "near" and "far" pragmas. (4) > One might use #pragma's to enable/disable debugging > or self-testing code. The preprocessor (remember the pre-processor? all and only # lines are to be handled by the preprocessor, which has usually been implemented as a **SEPARATE** program) is the wrong place to handle each of these things. (1) To the extent that I understand it, this is a task for the loader. The System V "COFF" loader will let you do all of this and more. So does the VMS loader. (2) The appropriate way to handle this is with pragma(device_register) struct devreg foo; or whatever. The preprocessor is for handling file inclusion, conditional inclusion, and macro definition and expansion. Not for giving half of a declaration! (3) Many 80x86 C compilers already have 'near' and 'far' as keywords, and I really don't think they are going to go away. Let's face it, "char *near" is a 16-bit (8086) or 32-bit (80386) data type, and "char *far" is a 32-bit (8086) or 48-bit (80386) data type, and something that fundamental belongs in the language, not in the preprocessor. So the appropriate thing to do is NOT to say #pragma near fred #pragma far jim char *fred, *jim; but char *pragma(near) jim; char *pragma(far) fred; (4) This IS an appropriate use of the preprocessor, but we already have #if. The way to do it is e.g. #if DEBUG void display_thing(const struct foo *p) { ... } #else #define display_thing(x) (void)(x) #endif It used to be the case back in Version 7 that there were two independent programs: the C preprocessor the C compiler When I say that they were independent, I mean that (a) the C preprocessor was available as a separate program which could be called directly and could be used as a front-end to ANYTHING with C-like lexical structure. E.g. Yacc, Ratfor, ... (b) the C compiler could be invoked without using the C preprocessor. (If the first character wasn't a #, the preprocessor was not used.) Every facility of the C language (including all the libraries) could be accessed without using the preprocessor. In the interests of portability, a lot of things have been shunted off into "standard" header files. With faster machines than PDP-11/34s, and with portability-via-standard-macros as a desideratum, property (b) is not very important any more. But property (a) is still useful. I have often used the C preprocessor as a front-end to other tools, and very useful it is. It seems to me that it would be a serious mistake to FORCE the preprocessor to be strongly coupled to the compiler. Now, is #pragma something which forces the preprocessor to be strongly coupled to the compiler, or not? Well, if #pragma can be used to declare properties of identifiers, either the preprocessor has to be built into the compiler or else it has to write something into its output stream which recodes the information and the compiler has to reparse it. In this latter case, there is a strong coupling between the preprocessor and its particular compiler, because they have to agree on how the pragma information is recoded. The trouble with declaring properties of identifiers in the preprocessor is the interaction of those declarations with C's scope rules. Suppose I say int fred; /* 1 */ void jim() #pragma device_register fred { static int fred; /* 2 */ ... Which fred was affected? I can think of at least four different interpretations, and each of them is "natural" and "obvious" given a different method of coupling the preprocessor and compiler. Now since the compiler is going to have to do something with this information anyway, the obvious thing to do is to be efficient and have only ONE program know about it, namely the compiler, and write pragma(device_register) int fred; /* 1 */ void jim() { static int fred; or int fred; void jim() { static pragma(device_register) int fred; /* 2*/ and make it absolutely clear which one we mean? I mean, let's face it, playmates, handling pragmas in the pre-processor makes about as much sense as handling "long" or "short" there.