เขียน C / C ++ Polyglot


27

แนวคิดของความท้าทายนี้ค่อนข้างง่าย สิ่งที่คุณต้องทำคือเขียนโปรแกรมที่จะรวบรวมเป็นทั้ง C ที่ถูกต้องและ C ++ ที่ถูกต้อง! มีบางอย่างที่จับได้ โปรแกรมจะต้องทำงานแตกต่างกันเมื่อรวบรวมในแต่ละภาษา โปรแกรมจะต้องมีเอาต์พุตที่แตกต่างกันสำหรับแต่ละภาษาเพื่อที่จะได้รับการพิจารณาว่า "ประพฤติแตกต่างกัน"

กฎระเบียบ

  • โปรแกรมจะต้องเป็นทั้ง C และ C ++ ที่ถูกต้อง
  • โปรแกรมจะต้องมีผลลัพธ์ที่แตกต่างกันขึ้นอยู่กับภาษาที่รวบรวมไว้
  • #ifdef __cplusplusหรือเทคนิค preprocessor "ง่าย" อื่น ๆ จะหมดกำลังใจ! (การดำเนินการตัวประมวลผลล่วงหน้าอื่น ๆ นั้นใช้ได้อย่างสมบูรณ์แบบ)
  • พยายามอย่าทำให้มันดูชัดเจนว่าโปรแกรมทำสิ่งที่แตกต่าง

นี่คือการดังนั้นใครก็ตามที่มีทางออกที่น่าสนใจและน่าประหลาดใจมากที่สุดชนะ มีความสุข!

ตัวอย่าง:

ฉันสร้างโปรแกรมของตัวเองเพื่อดูว่ามันเป็นไปได้ที่จะทำโดยใช้#ifdefเทคนิค:

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

โปรแกรมนี้แสดงผลC++ rules!เมื่อรวบรวมใน C ++ และC++ stinksเมื่อรวบรวมใน C

คำอธิบาย:

สิ่งที่ทำให้เกิดความแตกต่างระหว่างภาษาคือtr()ฟังก์ชั่น ใช้ประโยชน์จากหนึ่งในความแตกต่างระหว่าง C และ C ++ โดยเฉพาะอย่างยิ่งวิธีปฏิบัติต่อตัวอักษรถ่าน ใน C พวกเขาจะถือว่าเป็นจำนวนเต็มดังนั้นsizeof('!')ส่งกลับ 4 เมื่อเทียบกับ 1 ใน C ++ ((...+1)&1)ส่วนหนึ่งเป็นเพียงส่วนหนึ่งของการดำเนินการระดับบิตง่ายที่จะกลับ 1 ถ้าsizeof('!')ผลตอบแทน 4 และ 0 ถ้ามันกลับ 1. ส่งผลให้จำนวนคูณ ints ในอาร์เรย์tแล้วว่าผลิตภัณฑ์เป็นที่สุดที่เพิ่มให้กับตัวละครที่เฉพาะเจาะจงถูกเปลี่ยน ใน C ++ ผลิตภัณฑ์จะเป็นศูนย์เสมอดังนั้นสตริงC++ rules!จะยังคงไม่เปลี่ยนแปลง ใน C ผลิตภัณฑ์ที่จะเป็นค่าในและเพื่อให้สายการเปลี่ยนแปลงtC++ stinks


5
ฉันแน่ใจว่านี่เป็นสิ่งล่อใจของบางสิ่งบางอย่าง ...
Beta Decay

@BetaDecay มันคืออะไร? ฉันพยายามค้นหาสิ่งที่คล้ายกันและฉันไม่พบอะไรเลย
Mewy

คุณช่วยอธิบายวิธีการทำงานของโปรแกรมของคุณให้แตกต่างออกไปได้ (ถ้ามันไม่ทำให้เสียความท้าทาย)
อัล

@AL ฉันแก้ไขในคำอธิบายโพสต์ของฉัน
Mewy

stack ทั้งหมดจากstackoverflow.com/questions/2038200/…สามารถใช้ได้ที่นี่ - ด้วยความงุนงงเล็กน้อย
Jerry Jeremiah

คำตอบ:


18

เค้กโกหกหรือไม่?

เนื่องจากมีการถกเถียงกันมากว่าเค้กนั้นเป็นหรือไม่โกหกฉันจึงเขียนโปรแกรมนี้เพื่อตอบคำถามที่ถกเถียงกัน

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

ผลลัพธ์จะเป็นอย่างไร

C:

The cake is ..not a lie?

C ++:

The cake is a LIE!


1
นี้. ฉันชอบสิ่งนี้.
FUZxxl

9

แค่คนโง่

#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


บูลไม่ได้เป็นส่วนหนึ่งของ C89
malat

8
@malat Yep และความจริงข้อนี้ถูกนำมาใช้ในการแก้ปัญหานี้ สำหรับ c ++ ฟังก์ชั่นคือการทดสอบ int (อาร์กิวเมนต์บูลีน * * ไม่มีชื่อบูลีน * /); และสำหรับ C มันใช้การประกาศ int เริ่มต้นซึ่งหมายถึงการทดสอบ int (int บูล); ดังนั้น 'บูล' เป็นชื่อของตัวแปรจำนวนเต็ม
Qwertiy

5

ฉันสามารถทำสิ่งนี้ได้ด้วยโปรแกรม 3 บรรทัด แต่จะเห็นได้ชัดว่าทำไมมันถึงได้ผลลัพธ์ที่แตกต่างกันสำหรับ C และ C ++ ดังนั้นฉันเริ่มเขียนโปรแกรมที่ใหญ่กว่าด้วย stegonography ซึ่งได้ผลลัพธ์ที่แตกต่างใน C และ 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;
}

คุณต้องระบุบรรทัดคำสั่ง เมื่อฉันรันมันบนสำเนา gcc ของฉันฉันจะได้ผลลัพธ์นี้:

>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

สิ่งต่าง ๆ จะผิดพลาดได้อย่างไร?


แม้ว่าคนอื่นทำในสิ่งเดียวกันคุณก็สวมหน้ากากได้ดี
kirbyfan64sos


4

อันนี้ใช้ได้กับ C ++ 11 และใหม่กว่าและ C ใด ๆ จนถึงตอนนี้ (ก่อนหน้า C11)

#include <stdio.h>

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

ดูที่นี่: C ++: http://ideone.com/9Gkg75 และ C: http://ideone.com/eECSmr

มันใช้ประโยชน์จากข้อเท็จจริงที่ว่าใน C ++ 11 คำหลักอัตโนมัติมีความหมายใหม่ ดังนั้นในขณะที่ใน C เป็นประเภท int เก็บไว้ในตำแหน่ง AUTOmatic เป็นถ่านประเภทใน C ++ 11

แก้ไข: ในฐานะที่เป็น FUZxxl กล่าวว่า int นัยถูกลบใน C11


1
ไม่ทำงานกับ C11 เนื่องจาก C11 ได้ลบintกฎโดยนัยออกแล้ว
FUZxxl

@FZZxxl ขอบคุณฉันปรับโพสต์ของฉัน
เฟลิกซ์ Bytow

1

โปรแกรมอธิบายตนเอง

จะพิมพ์ "โปรแกรมนี้เขียนเป็นภาษา C!" ถ้ารวบรวมโดยใช้คอมไพเลอร์ C; มิฉะนั้นจะพิมพ์ "โปรแกรมนี้เขียนด้วย C ++!" มันต้องการคอมไพเลอร์ 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;}

โพสต์อื่น ๆ ส่วนใหญ่ใช้ประโยชน์จากความแตกต่างของขนาดของถ่านใน C vs C ++; อันนี้ใช้ความจริงที่ว่าใน C99 trueถูกกำหนดให้เป็นตัวเลข นี้แทรกเครื่องหมายอัศเจรีย์และเทอร์มิ null trueขึ้นอยู่กับขนาดของ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.