Scrivi un poliglotta C / C ++


27

Il concetto di questa sfida è piuttosto semplice. Tutto quello che devi fare è scrivere un programma che verrà compilato sia come C valido che come C ++ valido! Bene, ci sono alcune catture. Il programma deve comportarsi diversamente quando compilato in ciascuna lingua. Il programma deve avere un output diverso per ogni lingua per essere considerato "comportarsi diversamente".

Regole

  • Il programma deve essere valido sia in C che in C ++
  • Il programma deve avere output diversi in base alla lingua in cui è stato compilato.
  • #ifdef __cpluspluso altri trucchi "facili" per il preprocessore sono scoraggiati! (Tuttavia, altre operazioni del preprocessore vanno benissimo.)
  • Cerca di non far sembrare del tutto evidente che il programma fa qualcosa di diverso.

Questo è un , quindi vince chi ha la soluzione più interessante e sorprendente. Divertiti!

Esempio:

Ho creato il mio programma per vedere se ciò fosse possibile anche senza #ifdeftrucchi:

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

Questo programma genera C++ rules!quando compilato in C ++ e C++ stinksquando compilato in C.

Spiegazione:

Ciò che causa la differenza tra le lingue è la tr()funzione. Sfrutta una delle differenze tra C e C ++, in particolare il modo in cui vengono trattati i letterali char. In C, vengono trattati come numeri interi, quindi sizeof('!')restituisce 4, anziché 1 in C ++. La ((...+1)&1)parte è solo parte di una semplice operazione bit a bit che restituirà 1 se sizeof('!')restituisce 4 e 0 se restituisce 1. Quel numero risultante viene moltiplicato per gli ints nella matrice te quindi quel prodotto viene infine aggiunto al carattere specifico che viene trasformato. In C ++ il prodotto sarà sempre zero, quindi la stringa C++ rules!rimane invariata. In C, il prodotto sarà sempre il valore in te quindi la stringa cambia in C++ stinks.


5
Sono sicuro che questo è un inganno di qualcosa ...
Decadimento beta

@BetaDecay È? Ho provato a cercare qualcosa di simile e non sono riuscito a trovare nulla.
Mewy,

Puoi spiegare come funziona diversamente il tuo programma (se non rovina la sfida)?
AL

@AL Ho modificato in una spiegazione al mio post.
Mewy,

Tutti quelli da stackoverflow.com/questions/2038200/… potrebbero essere usati qui - con un po 'di offuscamento.
Jerry Jeremiah,

Risposte:


18

La torta è una bugia?

Dato che si è discusso molto sul fatto che la torta sia o meno una bugia, ho scritto questo programma per rispondere a questa domanda controversa.

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

Quale sarà il risultato?

C:

The cake is ..not a lie?

C ++:

The cake is a LIE!


1
Questo. Mi piace questo.
FUZxxl,

9

Solo alcuni bool

#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


bool non fa parte del C89
malat,

8
@malat Yep, e proprio questo fatto viene utilizzato in questa soluzione. Per c ++ la funzione è int test (bool / * argomento booleano senza nome * /); e per C usa la dichiarazione int predefinita che significa int test (int bool); quindi 'bool' è un nome di variabile intera.
Qwertiy,

5

Avrei potuto farlo con un programma a 3 righe, ma sarebbe ovvio il motivo per cui produce risultati diversi per C e C ++. Quindi, invece, ho iniziato a scrivere un programma più grande con qualche stegonografia che ottiene risultati diversi in C e 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;
}

Devi specificare una riga di comando. Quando lo eseguo sulla mia copia di gcc ottengo questo output:

>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

Come possono andare le cose in modo così orribilmente sbagliato?


Anche se altri hanno fatto la stessa cosa, l'hai mascherato abbastanza bene.
Kirbyfan64sos,

5
#include <stdio.h>

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

4

Questo funziona con C ++ 11 e successivi e qualsiasi C finora (prima di C11).

#include <stdio.h>

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

Vedi qui: C ++: http://ideone.com/9Gkg75 e C: http://ideone.com/eECSmr

Sfrutta il fatto che in C ++ 11 la parola chiave auto ha assunto un nuovo significato. Quindi mentre a in C è di tipo int memorizzato in una posizione AUTOmatic, è di tipo char in C ++ 11.

EDIT: Come FUZxxl ha detto che l'int implicito è stato rimosso in C11.


1
Non funziona con C11 poiché C11 ha rimosso la intregola implicita .
FUZxxl,

@FUZxxl Grazie, ho modificato il mio post.
Felix Bytow

1

Programma auto-descrittivo

Verrà stampato "Questo programma è scritto in C!" se compilato usando un compilatore C; in caso contrario, verrà stampato "Questo programma è scritto in C ++!". Ha bisogno di un compilatore 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;}

La maggior parte degli altri post sfrutta la differenza della dimensione di un carattere in C vs C ++; questo usa il fatto che, in C99, trueè definito come un numero. Ciò inserisce il punto esclamativo e il terminatore null in base alla dimensione di true.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.