编写一个程序,如果被编译为(ANSI) C程序,则打印"C";如果被编译为C++程序,则打印"C++"。

18
10个回答

49

1. 滥用C++自动typedef

(请注意,在C++中,struct需要在内部作用域中声明,以便优先于外部名称。)

#include <stdio.h>

int main(void)
{
    char x;

    {
        struct x { char dummy[2]; };
        printf("%s\n", sizeof (x) == 1 ? "C" : "C++");
    }
}

一种不依赖于sizeof (type)sizeof (variable)之间歧义的类似版本,仅使用类型:

#include <stdio.h>

int main(void)
{
    typedef char t;

    {
        struct t { char dummy[2]; };
        printf("%s\n", sizeof (t) == 1 ? "C" : "C++");
    }
}

2. 滥用C++中的struct/class等价性,自动typedef以及自动生成默认构造函数

#include <stdio.h>

int isC = 0;
void Foo() { isC = 1; }

int main(void)
{
    struct Foo { int dummy; };
    Foo();
    printf("%s\n", isC ? "C" : "C++");
}

3. 在C语言中滥用嵌套的struct声明

也可以参考C++与C中内部和外部结构体的符号冲突

#include <stdio.h>

int main(void)
{
    typedef struct inner { int dummy; } t;

    {
        struct outer { struct inner { t dummy[2]; } dummy; };
        printf("%s\n",
               sizeof (struct inner) == sizeof (t)
               ? "C++"
               : "C");
    }
}

4. 滥用 // 注释

这种方法对于 C99 或支持 // 扩展的 C89 编译器是不起作用的。

#include <stdio.h>

int main(void)
{
    printf("%s\n",
           0 //* */
           +1
           ? "C++"
           : "C");
}

或者,另一种选择是:
    printf("%s\n",
           1 //* */ 2
           ? "C++"
           : "C");

5. sizeofchar 字面量的差异

请注意,这并不保证可移植性,因为有可能某些假设的平台使用的字节超过了 8 位,这种情况下 sizeof(char) 可能与 sizeof(int) 相同。(另请参见 Can sizeof(int) ever be 1 on a hosted implementation?

#include <stdio.h>

int main(void)
{
    printf("%s\n", sizeof 'a' == 1 ? "C++" : "C");
}

6. 滥用lvalue⇒rvalue转换执行的时差

这是基于ISO C++03标准中5.16、5.17和5.18示例,并且在gcc中有效但在MSVC中无效(可能由于编译器错误?)。

#include <stdio.h>

int main(void)
{
    void* array[2];
    printf("%s\n",
           (sizeof (((void) 0), array) / sizeof (void*) == 1)
           ? "C"
           : "C++");
}

7. 滥用C和C++语法解析三目运算符的差异

这个方法并不严格合法,但是一些编译器比较宽松。

#include <stdio.h>

int main(void)
{
    int isCPP = 1;
    printf("%s\n", (1 ? isCPP : isCPP = 0) ? "C++" : "C");
}

你也可以检查__cplusplus预处理宏(或其他各种宏),但我认为这不符合问题的本意。

我已经实现了所有这些内容,网址如下: http://www.taenarum.com/csua/fun-with-c/c-or-cpp.c


1
我非常确定标准要求char为1字节,byte为8位。 - jalf
6
根据定义,char 是 1 字节,而一个字节至少包含 8 位,但也可能更多。这就是为什么会有 CHAR_BIT 的存在。 - jamesdlin
2
需要char为1个字节。一个字节中的位数是实现定义的。 - avakar
3
一种答案中,其中一个选项是不可携带的,而其他六个选项被描述为虐待,真是令人爱不释手啊 :-) - paxdiablo
1
@jacques 在 C 语言中,声明 struct 的典型方式是使用类型为 struct xstruct x { ... } 结构体。如果你想要一个 typedef,这样在使用时就不需要每次都输入 struct,你可以这样做:typedef struct x { ... } simpler_name。请注意,struct 标签x)和 typedefsimpler_name)存在于不同的 C 命名空间中,因此你也可以这样做:typedef struct x { ... } x。C++ 会隐式地为 structclass 创建这样的 typedef,因此在 C++ 中,方法 #1 中的 x 与 C 中的解析方式不同。 - jamesdlin
显示剩余2条评论

44

我们在学校也曾经做过类似的作业。除了#include之外,我们不允许使用预处理器。下面的代码利用了C语言中类型名称和结构体名称形成独立命名空间的事实,而在C ++中则没有。

#include <stdio.h>
typedef int X;
int main()
{
    struct X { int ch[2]; };
    if (sizeof(X) != sizeof(struct X))
        printf("C\n");
    else
        printf("C++\n");
}

2
在C++中,它们并不是不形成单独的命名空间,而是由编译器保持分离,但是编译器将在两个命名空间中查找符号(首先在非用户定义类型中,然后在用户定义类型中)。有几种测试方法,其中最简单的是typedef struct X {} Y; void X();可以编译,但如果添加void Y();,则会出现编译器错误:在非用户定义的命名空间中已经使用了符号Y,这是由于typedef - David Rodríguez - dribeas

31

非常简单。

#include <stdio.h>
int main(int argc, char ** argv) {
#ifdef __cplusplus
printf("C++\n");
#else
printf("C\n");
#endif
return 0;
}

还是说有没有必要在不使用官方标准的情况下完成这个需求?


2
刚刚让输出与问题相符。 - anon
2
没错。C++ 1998标准规定:“当编译一个C++翻译单元时,名称__cplusplus被定义为值199711L”。(第16.8节:[cpp.predefined]) - stakx - no longer contributing
10
当然,一个极其恶劣的C语言实现可以定义__cplusplus。 - anon
4
只有编译器完全符合标准,才会将__cplusplus定义为199711L。例如,gcc仍将__cplusplus定义为1。 - kennytm
7
在C99标准的第6.10.8.5节中,明确禁止实现定义__cplusplus。但在C89中并没有类似的规定。@Neil - Nicolas Goy
显示剩余3条评论

16
puts(sizeof('a') == sizeof(int) ? "C" : "C++");

6
这实际上不能保证可行。如果 CHAR_BIT 至少为 16,sizeof(int) 可能为 1。 - avakar
8
在C语言中,单引号括起来的字符字面量属于“int”类型,在C++中则属于“char”类型。 - avakar

3

以下是程序代码:

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("This is %s\n", sizeof 'a' == sizeof(char) ? "C++" : "C");
    return 0;
}

这里有一些关于C和C++区别的好文章,点击这里


2

只需要查看编译器宏__STDC____cplusplus是否已定义。


1

我猜测意图是编写一些依赖于语言本身差异而非预定义宏的内容。虽然从技术上讲不能完全保证其可行性,但像这样的方法可能更接近所需的效果:

int main() { 
    char *names[] = { "C", "C++"};

    printf("%s\n", names[sizeof(char)==sizeof('C')]);
    return 0;
}

1
与Matthew Slattery一样,这可能在所有平台上都无法正常工作。 - avakar
@avakar: 理论上来说是有点真的——这就是为什么我说它不是绝对保证能够工作。同时,C语言I/O库的基本设计依赖于EOF与任何无符号字符值不同。这意味着sizeof(int)>sizeof(unsigned char)。尽管曾经有个想法认为sizeof(char)==sizeof(int)应该被允许,但实际上要使C语言以那种方式工作是不可能的,所以上面的代码确实是可靠的。 - Jerry Coffin
1
@avakar 是正确的,这并不保证可行:有可能 sizeof(int) == 1 并且所有 int 值都是有效的字符返回值从 getchar(),在这种情况下 EOF 也可以是一个有效的字符,并且需要使用 feof()(和使用 ferror() 进行错误测试)来测试 EOF 是否表示文件结束。Cray 就是 sizeof(int) == 1 的一个例子:它们曾经将所有整数类型都设置为 64 位宽度。 - JaakkoK
1
@jlk:就像我说的,在理论上,它有点正确。但实际上,一个与int相同大小的字符实现会破坏很多代码,从而导致没有人使用它。关于Cray计算机,所有整数类型具有相同大小的想法是一个城市传说——一种谣言,尽管反复测试表明如果它曾经真实存在,那只是通过一种从未发布到外部世界的编译器(也没有证据表明它曾经在内部存在)。 - Jerry Coffin
@Jerry:还可以参考我的问题https://dev59.com/tG865IYBdhLWcg3wWtKz - R.. GitHub STOP HELPING ICE
显示剩余4条评论

1
一个词,__cplusplus

0

说句实话,这里还有一个答案:

char x[sizeof(char *)+2], y[1];
printf("%.*s\n", sizeof(1?x:y)-sizeof(char *)+1, "C++");

我尝试使用gcc和g ++编译以下代码http://pastebin.com/zsxX1NNN。文件分别保存为foo.c和foo.cpp。两次都打印了C。我认为你的做法不应该奏效,因为指针的大小取决于架构。 - Xolve
也许我的想法是错误的。我以为在这种情况下,数组不会在C++中衰减为指针... - R.. GitHub STOP HELPING ICE

-1
你可以尝试使用预处理指令,但这可能不是他们想要的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接