Écrire un polyglotte C / C ++

27

Le concept de ce défi est assez simple. Tout ce que vous avez à faire est d'écrire un programme qui se compilera en C valide et en C ++ valide! Eh bien, il y a des captures. Le programme doit se comporter différemment lorsqu'il est compilé dans chaque langue. Le programme doit avoir une sortie différente pour chaque langue afin d'être considéré comme "se comportant différemment".

Règles

  • Le programme doit être à la fois C et C ++ valide
  • Le programme doit avoir des sorties différentes en fonction de la langue dans laquelle il a été compilé.
  • #ifdef __cplusplusou d'autres astuces de préprocesseur "faciles" sont déconseillées! (Cependant, d'autres opérations de préprocesseur sont parfaitement correctes.)
  • Essayez de ne pas rendre complètement évident que le programme fait quelque chose de différent.

C'est un , donc celui qui a la solution la plus intéressante et surprenante gagne. S'amuser!

Exemple:

J'ai créé mon propre programme pour voir si c'était même possible de le faire sans #ifdeftrucs:

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

Ce programme sort C++ rules!lorsqu'il est compilé en C ++ et C++ stinkslorsqu'il est compilé en C.

Explication:

Ce qui cause la différence entre les langues, c'est la tr()fonction. Il tire parti de l'une des différences entre C et C ++, en particulier, la façon dont les littéraux char sont traités. En C, ils sont traités comme des entiers, donc sizeof('!')renvoie 4, par opposition à 1 en C ++. La ((...+1)&1)partie n'est qu'une partie d'une opération au niveau du bit simple qui renverra 1 si sizeof('!')renvoie 4 et 0 si elle renvoie 1. Ce nombre résultant est multiplié par les entrées dans le tableau t, puis ce produit est finalement ajouté au caractère spécifique en cours de transformation. En C ++, le produit sera toujours nul, donc la chaîne C++ rules!reste inchangée. En C, le produit sera toujours la valeur en t, et donc la chaîne passe à C++ stinks.

Mewy
la source
5
Je suis sûr que c'est une dupe de quelque chose ...
Beta Decay
@BetaDecay Est-ce? J'ai essayé de chercher quelque chose de similaire et je n'ai rien trouvé.
Mewy
Pouvez-vous expliquer comment votre programme fonctionne différemment (s'il ne gâche pas le défi)?
AL
@AL J'ai édité une explication à mon message.
Mewy
Tous ceux de stackoverflow.com/questions/2038200/… pourraient être utilisés ici - avec un peu d'obscurcissement.
Jerry Jeremiah

Réponses:

18

Le gâteau est-il un mensonge?

Comme il y a eu beaucoup de débats pour savoir si le gâteau est ou non un mensonge, j'ai écrit ce programme pour répondre à cette question controversée.

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

Quel sera le résultat?

C:

The cake is ..not a lie?

C ++:

The cake is a LIE!

es1024
la source
1
Cette. J'aime ça.
FUZxxl
9

Juste quelques bools

#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
la source
bool ne fait pas partie C89
malat
8
@malat Yep, et c'est exactement ce fait qui est utilisé dans cette solution. Pour c ++, la fonction est int test (bool / * argument booléen sans nom * /); et pour C, il utilise la déclaration int par défaut qui signifie int test (int bool); donc 'bool' est un nom de variable entière.
Qwertiy
5

J'aurais pu le faire avec un programme en 3 lignes mais alors il serait évident pourquoi il produit des résultats différents pour C et C ++. Au lieu de cela, j'ai commencé à écrire un plus gros programme avec une stégonographie qui obtient des résultats différents en C et 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;
}

Vous devez spécifier une ligne de commande. Lorsque je l'exécute sur ma copie de gcc, j'obtiens cette sortie:

>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

Comment les choses peuvent-elles aller si horriblement mal?

Jerry Jeremiah
la source
Bien que d'autres aient fait la même chose, vous l'avez assez bien masqué.
kirbyfan64sos
5
#include <stdio.h>

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

Celui-ci fonctionne avec C ++ 11 et plus récent et tout C jusqu'à présent (avant C11).

#include <stdio.h>

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

Voir ici: C ++: http://ideone.com/9Gkg75 et C: http://ideone.com/eECSmr

Il exploite le fait qu'en C ++ 11, le mot clé auto a pris un nouveau sens. Ainsi, si un in C est de type int stocké dans un emplacement AUTOmatic, il est de type char en C ++ 11.

EDIT: Comme FUZxxl l'a dit, l'intim implicite a été supprimé dans C11.

Felix Bytow
la source
1
Ne fonctionne pas avec C11 car C11 a supprimé la intrègle implicite .
FUZxxl
@FUZxxl Merci, j'ai ajusté mon message.
Felix Bytow
1

Programme auto-descriptif

Cela imprimera "Ce programme est écrit en C!" si compilé à l'aide d'un compilateur C; sinon, il affichera "Ce programme est écrit en C ++!". Il a besoin d'un compilateur 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 plupart des autres publications profitent de la différence de taille d'un caractère en C vs C ++; celui-ci utilise le fait que, en C99, trueest défini comme un nombre. Cela insère le point d'exclamation et le terminateur nul en fonction de la taille de true.

kirbyfan64sos
la source