Pergunta

The following program looks like a C macro that calls itself.

#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(#define q(k)int puts();int main(){puts(#k"\nq("#k")");})

It compiles and runs fine. It prints itself out.

Is this code really C? That is, does it rely on anything outside of standard C to work correctly?

@devnull pointed out that this question has a similar program:

#define q(k)main(){return!puts(#k"\nq("#k")");}
q(#define q(k)main(){return!puts(#k"\nq("#k")");})

Does this program rely on anything outside of standard C to work correctly?

Foi útil?

Solução

The first program is an example of an implementation of a quine in C. At a high level, it defines a macro q() which creates a definition of main() that prints out two lines. The first line is the argument by itself, the second line is the argument wrapped in a call to q() itself. So, the following program:

#define q(k)int puts();int main(){puts(#k"\nq("#k")");}
q(foo)

Expands into:

int puts();int main(){puts("foo""\nq(""foo"")");}

When compiled and run, it results in the output:

foo
q(foo)

Substituting the macro definition itself in place of foo results in a quine. The macro does not really invoke itself, it is invoked on the same text that defines it. In C, macros are not expanded recursively (C.99 §6.10.3.4 ¶2).

As noted in the question, the program compiles without complaint under GCC using strict C.99 settings (-pedantic -std=c99). The program uses only standard C features, and conforms to both C.99 and C.11.

  • Macro replacement (C.99 §6.10.3), with argument substituion (C.99 §6.10.3.1) and the # "stringifying" operator (C.99 §6.10.3.2).
  • Function declaration with unspecified argument list (C.99 §6.7.5.3 ¶14).
  • String literal concatenation (C.99 §5.1.1.2 ¶1).
  • Default main() return value (C.99 §5.1.2.2.3 ¶1).

Of particular note, the program does not rely on ASCII encoding of characters.

The program will compile on a C.89-90 compiler, but the behavior of not returning a value from main() is not defined for C.89-90. The program can be trivially modified to become C.89-90 compliant by adding return 0; after the call to puts().

As to the second program, it is also a quine. However, it is not C.89-90, nor C.99, nor C.11 compliant. This is because it relies on puts() to return a positive number for the logical-not operator so that the return value is 0. However, C only requires the puts() return a non-negative value on success (C.99 §7.19.7.10 ¶3). Only C.89-90 permits implicit function declarations (C.89, §3.3.2.2). The program can be modified to conform to C.89-90 by removing return!, and then adding return 0; after the puts() call.

The structure of these programs is largely inspired by an implementation of a quine program in the "fictional" language BlooP, presented in the book Gödel, Escher, Bach: An Eternal Golden Braid, by Douglas R. Hofstadter (credited for having coined the term quine).

DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET,
QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD].
ENIUQ
['DEFINE PROCEDURE "ENIUQ" [TEMPLATE]: PRINT [TEMPLATE, LEFT-BRACKET,
QUOTE-MARK, TEMPLATE, QUOTE-MARK, RIGHT-BRACKET, PERIOD].
ENIUQ'].

As an aside, here is a version of the program that prints out its source code in reverse order:

#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");}
q(#define q(k)r(char*s){if(*s)r(s+1);putchar(*s);}main(){r(#k"\nq("#k")\n");})
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top