Napisz C / C ++ Polyglot

27

Koncepcja tego wyzwania jest dość prosta. Wszystko, co musisz zrobić, to napisać program, który skompiluje się zarówno jako poprawny C, jak i poprawny C ++! Cóż, są pewne połowy. Program musi zachowywać się inaczej po skompilowaniu w każdym języku. Program musi mieć różne dane wyjściowe dla każdego języka, aby można go było uznać za „zachowujący się inaczej”.

Zasady

  • Program musi mieć poprawne C i C ++
  • Program musi mieć różne wyniki w zależności od języka, w którym został skompilowany.
  • #ifdef __cpluspluslub inne „łatwe” sztuczki preprocesora są odradzane! (Inne operacje preprocesora są jednak całkowicie w porządku).
  • Staraj się, aby nie wydawało się to całkowicie oczywiste, że program robi coś innego.

To , więc wygrywa ten, kto ma najbardziej interesujące i zaskakujące rozwiązanie. Baw się dobrze!

Przykład:

Stworzyłem własny program, aby sprawdzić, czy można to zrobić bez #ifdefsztuczek:

#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;
}

Ten program generuje dane C++ rules!po skompilowaniu w C ++ i C++ stinkspo kompilacji w C.

Wyjaśnienie:

To, co powoduje różnicę między językami, to tr()funkcja. Wykorzystuje jedną z różnic między C i C ++, a konkretnie sposób traktowania literałów char. W C są one traktowane jako liczby całkowite, więc sizeof('!')zwraca 4, w przeciwieństwie do 1 w C ++. ((...+1)&1)Część jest tylko część prostą operację logiczną, która zwraca 1 jeżeli sizeof('!')wraca 4, oraz 0, gdy powraca 1. Tak otrzymaną ilość jest mnożona przez wskazówki w tablicy t, a następnie produkt ten koniec dodaje się do konkretnych postaci są transformowane. W C ++ produkt zawsze będzie wynosił zero, więc ciąg znaków C++ rules!pozostaje niezmieniony. W C iloczyn zawsze będzie wartością w t, więc łańcuch zmienia się na C++ stinks.

Mewy
źródło
5
Jestem pewien, że jest to duplikat czegoś ...
Rozpad
@BetaDecay Czy to jest? Próbowałem szukać czegoś podobnego i nic nie mogłem znaleźć.
Mewy
Czy możesz wyjaśnić, w jaki sposób Twój program działa inaczej (jeśli nie psuje wyzwania)?
AL
@AL Edytowałem w wyjaśnieniu do mojego postu.
Mewy
Wszystkie te z stackoverflow.com/questions/2038200/... mogą być tutaj użyte - z niewielkim zaciemnieniem.
Jerry Jeremiah

Odpowiedzi:

18

Czy to kłamstwo?

Ponieważ trwało wiele dyskusji na temat tego, czy ciasto jest kłamstwem, napisałem ten program, aby odpowiedzieć na to sporne pytanie.

#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;
}

Jaki będzie wynik?

DO:

The cake is ..not a lie?

C ++:

The cake is a LIE!

es1024
źródło
1
To. Lubię to.
FUZxxl
9

Tylko trochę booli

#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
źródło
bool nie jest częścią C89
malat
8
@malat Tak, i właśnie ten fakt został wykorzystany w tym rozwiązaniu. W przypadku c ++ funkcją jest test int (bool / * nienazwany argument boolean * /); a dla C używa domyślnej deklaracji int, co oznacza int test (int bool); więc „bool” to nazwa zmiennej całkowitej.
Qwertiy,
5

Mógłbym to zrobić za pomocą 3-liniowego programu, ale wtedy byłoby oczywiste, dlaczego produkuje różne wyniki dla C i C ++. Zamiast tego zacząłem pisać większy program z pewną stegonografią, który uzyskuje różne wyniki w C i C ++ ...

#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;
}

Musisz podać wiersz polecenia. Kiedy uruchomię go na mojej kopii gcc, otrzymuję ten wynik:

>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

Jak sprawy mogą potoczyć się tak okropnie źle?

Jerry Jeremiasz
źródło
Chociaż inni robili to samo, całkiem dobrze to zamaskowałeś.
kirbyfan64sos
5
#include <stdio.h>

int c[1]; 
int main() { 
   struct c { int cpp[2]; }; 
   printf("%d\n", (int)sizeof(c)/4);
}
Wyświetlana nazwa
źródło
4

Ten działa z C ++ 11 i nowszymi oraz dowolnym C do tej pory (przed C11).

#include <stdio.h>

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

Zobacz tutaj: C ++: http://ideone.com/9Gkg75 i C: http://ideone.com/eECSmr

Wykorzystuje fakt, że w C ++ 11 słowo kluczowe auto zyskało nowe znaczenie. Tak więc, podczas gdy in C jest typu int przechowywane w lokalizacji AUTOmatic, jest typu char w C ++ 11.

EDYCJA: Jak powiedział FUZxxl, domyślna int została usunięta w C11.

Felix Bytów
źródło
1
Nie działa z C11, ponieważ C11 usunął domyślną intregułę.
FUZxxl
@FUZxxl Dzięki, dostosowałem swój post.
Felix Bytow
1

Program samoopisujący

Spowoduje to wydrukowanie „Ten program jest napisany w C!” jeśli skompilowany przy użyciu kompilatora C; w przeciwnym razie wypisze „Ten program jest napisany w C ++!”. Potrzebuje kompilatora C99.

#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;}

Większość innych postów korzysta z różnicy wielkości znaku w C w porównaniu z C ++; ten wykorzystuje fakt, że w C99 truejest zdefiniowany jako liczba. Powoduje to wstawienie wykrzyknika i terminatora zerowego w zależności od rozmiaru true.

kirbyfan64sos
źródło