Schreiben Sie einen C / C ++ - Polyglot

27

Das Konzept dieser Herausforderung ist ziemlich einfach. Sie müssen lediglich ein Programm schreiben, das sowohl als gültiges C als auch als gültiges C ++ kompiliert wird! Nun, es gibt einige Fänge. Das Programm muss sich beim Kompilieren in jeder Sprache anders verhalten. Das Programm muss für jede Sprache eine andere Ausgabe haben, um als "anders verhalten" zu gelten.

Regeln

  • Das Programm muss sowohl in C als auch in C ++ gültig sein
  • Das Programm muss abhängig von der Sprache, in der es kompiliert wurde, unterschiedliche Ausgaben haben.
  • #ifdef __cplusplusoder andere "einfache" Präprozessor-Tricks sind nicht zu empfehlen! (Andere Präprozessoroperationen sind jedoch völlig in Ordnung.)
  • Versuchen Sie nicht ganz offensichtlich zu machen, dass das Programm etwas anderes macht.

Dies ist ein , bei dem jeder gewinnt, der die interessanteste und überraschendste Lösung hat. Habe Spaß!

Beispiel:

Ich habe mein eigenes Programm erstellt, um zu sehen, ob dies überhaupt mit unseren #ifdefTricks möglich ist:

#include <stdio.h>
#include <string.h>

char *m="C++ rules!";

int t[11]={0,0,0,0,1,-1,-3,9,-8,82,0};

char tr(char c,int i)
{
    return c+((sizeof('!')+1)&1)*t[i];
}

int main()
{
    int i = 0;
    for(;i<strlen(m);i++)
    {
        printf("%c",tr(m[i],i));
    }
    printf("\n");
    return 0;
}

Dieses Programm wird C++ rules!beim Kompilieren in C ++ und C++ stinksbeim Kompilieren in C ausgegeben.

Erläuterung:

Was den Unterschied zwischen den Sprachen verursacht, ist die tr()Funktion. Dabei wird einer der Unterschiede zwischen C und C ++ ausgenutzt, insbesondere, wie Zeichenliterale behandelt werden. In C werden sie als Ganzzahlen behandelt, daher wird sizeof('!')4 im Gegensatz zu 1 in C ++ zurückgegeben. Der ((...+1)&1)Teil ist nur ein Teil einer einfachen bitweisen Operation, die 1 sizeof('!')zurückgibt, wenn 4 zurückgegeben wird, und 0, wenn 1 zurückgegeben wird. Diese resultierende Zahl wird mit den ints in array multipliziert, tund dieses Produkt wird schließlich zu dem spezifischen Zeichen hinzugefügt, das transformiert wird. In C ++ ist das Produkt immer Null, sodass die Zeichenfolge C++ rules!unverändert bleibt. In C ist das Produkt immer der Wert in t, und daher ändert sich die Zeichenfolge in C++ stinks.

Mewy
quelle
5
Ich bin mir sicher, dass dies ein Betrug von etwas ist ...
Beta Decay
@BetaDecay Ist es? Ich habe versucht, nach etwas Ähnlichem zu suchen und konnte nichts finden.
Mewy
Können Sie bitte erklären, wie Ihr Programm anders funktioniert (wenn es die Herausforderung nicht trübt)?
AL
@AL Ich habe in einer Erklärung zu meinem Beitrag bearbeitet.
Mewy
Alle von stackoverflow.com/questions/2038200/… könnten hier verwendet werden - mit ein wenig Verschleierung.
Jerry Jeremiah

Antworten:

18

Ist der Kuchen eine Lüge?

Da viel darüber diskutiert wurde, ob der Kuchen eine Lüge ist oder nicht, habe ich dieses Programm geschrieben, um diese umstrittene Frage zu beantworten.

#include <stdio.h>

// checks if two things are equal
#define EQUALS(a,b) (sizeof(a)==sizeof(b)) 

struct Cake{int Pie;}; // the cake is a pie!
typedef struct Cake Lie;
main(){
    struct CakeBox{
        struct Cake{ // the cake contains lies!
            Lie Lies[2];
        };
    };
    typedef struct Cake Cake;

    printf("The cake is ");
    if(EQUALS(Cake, Lie)){
        printf("a LIE!\n");
    }else{
        printf("..not a lie?\n");
    }
    return 0;
}

Was wird das Ergebnis sein?

C:

The cake is ..not a lie?

C ++:

The cake is a LIE!

es1024
quelle
1
Dies. Ich mag das.
FUZxxl
9

Nur ein paar Idioten

#include <stdio.h>

int test(bool)
  {
  return sizeof(bool) == sizeof(int);
  }

int main(void)
  {
  puts(test(0) ? "C" : "C++");
  return 0;
  }

http://codepad.org/dPFou20W
http://codepad.org/Ko6K2JBH

Qwertiy
quelle
bool ist nicht Teil von C89
malat 20.11.14
8
@malat Yep, und genau diese Tatsache wird in dieser Lösung verwendet. Für c ++ lautet die Funktion int test (bool / * unbenanntes boolesches Argument * /); und für C wird die int-Standarddeklaration verwendet, die int test (int bool) bedeutet; 'bool' ist also ein Name einer Ganzzahlvariablen.
Qwertiy
5

Ich hätte das mit einem 3-zeiligen Programm machen können, aber dann wäre klar, warum es für C und C ++ unterschiedliche Ergebnisse liefert. Also habe ich stattdessen angefangen, ein größeres Programm mit Stegonographie zu schreiben, das in C und C ++ unterschiedliche Ergebnisse liefert ...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct product
{
    int quantity;
    char name[20];
    char desc[80];
}; 

struct _customer
{
    char name[80];
    struct product *products;
} customer;

int main(int argc, char *argv[])
{

struct shipment
{
    char tracking_number[40];
    int quantity;
    struct product { int model; int serial; } sku;
};

struct _supplier
{
    char name[80];
    struct shipment *shipments;
} supplier;

/* now read the command line and allocate all the space we need */

if(argc<5)
{
    printf("Usage: %s <supplier name> <# of shipments> <customer name> <# of products> ",argv[0]);
    exit(1);
}

strcpy(supplier.name,argv[1]);
int shipments_size = atoi(argv[2])*sizeof(struct shipment);
printf("Allocating %d bytes for %s shipments\n", shipments_size,supplier.name);
supplier.shipments=(struct shipment *)malloc(shipments_size);

strcpy(customer.name,argv[3]);
int products_size = atoi(argv[4])*sizeof(struct product);
printf("Allocating %d bytes for %s products\n", products_size,customer.name);

/* ... TODO ... finish the rest of this program later */

free(customer.products);
free(supplier.shipments);

return 0;
}

Sie müssen eine Befehlszeile angeben. Wenn ich es auf meiner Kopie von gcc laufen lasse, erhalte ich diese Ausgabe:

>g++ x.cpp

>a.exe "Bob Supplier" 1 "Jane Customer" 1
Allocating 52 bytes for Bob Supplier shipments
Allocating 104 bytes for Jane Customer products

>gcc x.c

>a.exe "Bob Supplier" 1 "Jane Customer" 1
Allocating 52 bytes for Bob Supplier shipments
Allocating 8 bytes for Jane Customer products

Wie können die Dinge so schrecklich schief gehen?

Jerry Jeremiah
quelle
Obwohl andere dasselbe taten, haben Sie es ziemlich gut maskiert.
kirbyfan64sos
5
#include <stdio.h>

int c[1]; 
int main() { 
   struct c { int cpp[2]; }; 
   printf("%d\n", (int)sizeof(c)/4);
}
Anzeigename
quelle
4

Dieser funktioniert mit C ++ 11 und neueren und allen bisherigen C-Versionen (vor C11).

#include <stdio.h>

int main()
{
    auto a = 'a';
    printf(sizeof(a) == sizeof(int) ? "C\n" : "C++\n");
    return 0;
}

Siehe hier: C ++: http://ideone.com/9Gkg75 und C: http://ideone.com/eECSmr

Es nutzt die Tatsache aus, dass das Schlüsselwort auto in C ++ 11 eine neue Bedeutung erhalten hat. Während also ein in C vom Typ int ist, der an einer AUTOmatic-Position gespeichert ist, ist es in C ++ 11 vom Typ char.

EDIT: Wie FUZxxl sagte, wurde das implizite int in C11 entfernt.

Felix Bytow
quelle
1
Funktioniert nicht mit C11, da C11 die implizite intRegel entfernt hat.
FUZxxl
@FUZxxl Danke, ich habe meinen Beitrag angepasst.
Felix Bytow
1

Selbstbeschreibendes Programm

Dies wird "Dieses Programm ist in C geschrieben!" wenn mit einem C-Compiler kompiliert; Andernfalls wird "Dieses Programm ist in C ++ geschrieben!" Es benötigt einen C99-Compiler.

#include <stdbool.h>
#include <stdio.h>
char str[] = "This program is written in C++ ";
#define S (sizeof(str)-sizeof(true)-sizeof(true)%4)
int main(){for(int i=S;i<=S+1;++i)str[i]=i==S?'!':'\0';puts(str);return 0;}

Die meisten anderen Posts nutzen den Unterschied zwischen der Größe eines Zeichens in C und C ++. Dieser verwendet die Tatsache, dass in C99 truedefiniert ist, eine Zahl zu sein. Hiermit werden das Ausrufezeichen und das Null-Abschlusszeichen basierend auf der Größe von eingefügt true.

kirbyfan64sos
quelle