可以用c而不是c ++做什么?

时间:2010-10-07 07:46:45

标签: c++ c

在C语言中可以完成哪些事情,而在C ++中却没有,在C ++中进行编码时,您最想念的是哪些功能?

我能想到的几件事情:

  1. 我们可以将任何类型的指针指定给void指针,而不是在c中而不是在c ++中。
  2. 声明变量名称,这些变量名称是C ++中的关键字,但不是C;)
  3. 编辑:谢谢@sbi指出:
    1.应该是:我们可以为C中的任何类型的指针分配void指针,但不能在C ++中指定

13 个答案:

答案 0 :(得分:37)

答案 1 :(得分:17)

您可能会发现网页Incompatibilities Between ISO C and ISO C++很有趣。

我大多错过了C ++中没有的一些C99功能:

  • 复合文字;
  • 指定的初始化程序;
  • 变量参数宏(包含在C ++ 0X中)。

答案 2 :(得分:15)

不是 C中的功能,但可以说是 C的杀手级功能,C89的简单语法使编写编译器变得容易。好吧,无论如何,与C ++编译器相比。

答案 3 :(得分:4)

  
      
  1. 我们可以将任何类型的指针指定给void指针,而不是在c中而不是在c ++中。
  2.   

任何指针也可以在C ++中转换为void*。你正在以这种方式丢失信息,编译器也不会阻止你这样做。这是一个问题的反面,因为这样你就获得了编译器无法检查的信息。

我认为C允许这样做,而C ++肯定没有。

答案 4 :(得分:3)

如果我们忽略了显而易见的差异来源--C99 - 将自己限制在C89 / 90,并且还丢弃了像C ++关键字这样的平凡变体,那么C和C ++之间仍然存在一些差异

(1)您已经提到了在没有强制转换的情况下将void *转换为任何具体指针类型的能力。

(2)具有“未指定”参数的函数类型,即函数类型声明中的()。在C中你可以这样做

void foo(int, int);
void bar(double);

int main() {
  void (*pf)();

  pf = foo;
  pf(1, 2); /* valid call */

  pf = bar;
  pf(5.0);  /* valid call */
}

这在C ++中是不可能的。当然,也可以说一般的非原型函数声明是C的一个特性,它在C ++中不存在(也适用于C99)。

(3)数组初始化与字符串文字的一些区别:允许尾随\0在C中脱落,但在C ++中不允许

char str[2] = "ab"; /* valid C, not valid C++ */

(4)C中的暂定定义,尽管它们几乎没有任何后果。

(5)另一个非常无关紧要的“特征”:在C中,你可以使用“忘记”实际返回任何东西的值返回函数

int foo() {
}

代码在C和C ++中都是合法的,但在C ++中,这样的函数会无条件地产生未定义的行为。在C中,只有在您实际尝试使用返回值

时,该函数才会产生未定义的行为
foo(); /* fine in C, undefined behavior in C++ */

(6)如果我记得它,我会稍后添加一些其他的东西。

答案 5 :(得分:2)

您可以在C中使用variable-length array但在C ++中不能。我相信这将非常有用,而不是为此做new[]

答案 6 :(得分:2)

在C中,您可以隐式地在void指针和其他指针之间进行转换,但是您必须在C ++中进行显式转换。

void* void_ptr;
int* int_ptr;

int_ptr = void_ptr;  // Invalid in C++, but not in C
void_ptr = int_ptr;  // Valid in C and C++
void_ptr = (void*)int_ptr; // Valid in C and C++
int_ptr = (int*)void_ptr;  // Valid in C and C++

答案 7 :(得分:2)

语法糖和类型滥用有一些微妙的差异,但它们很容易解决。

C最重要的功能是生成完全独立的程序,绝对没有外部依赖。这就是为什么操作系统内核几乎普遍用C语言编写的原因.C实际上是为实现操作系统而设计的。可以在C ++的受限子集中编写OS内核,但强制执行这些限制只发生在链接时(如果有的话),因此处理它比处理次要语法差异要大得多。

答案 8 :(得分:1)

我喜欢C语言的能力是看a = b;之类的东西,并确切知道它在做什么。在C ++中,任何人都可以覆盖运算符,这意味着像这样的简单语句最终可能会调用一些大型复制构造函数(或者更糟糕的是,完全不相关的东西)。你在C ++中看到a = b;,你必须猜测(或者去查找)是否有人这样做只是为了讨厌。

答案 9 :(得分:0)

作为C的粉丝,我认为编码风格的概念可能还有另一点,那就是函数式编程,与面向对象的编程相比,称为OOP!对于那些将代码编写为状态机的人来说,这是一个非常有趣的概念!将opengl视为一个很好的例子。由于较少的内存引用,在C中运行代码的速度也非常好。您可能也喜欢听到许多程序员喜欢用C语言编写代码,因为它们的设计简单,以及如何使用它们(语法可能不那么容易)。哦,当你想编写非常接近硬件级别的代码时,你应该使用纯C。

答案 10 :(得分:0)

C99遗漏的功能之一是VLA,C ++应该没有等效功能。

有些人甚至质疑在C ++中写一个类似VLA的对象的可能性。

这就是为什么我添加了这个答案:尽管略微偏离主题,它仍然表明,使用正确的库,C ++开发人员仍然可以访问模仿C99功能的对象。因此,这些特征并不像想象的那样错过。

主要代码是:

#include <iostream>
#include <string>
#include "MyVLA.hpp"

template <typename T>
void outputVLA(const std::string & p_name, const MyVLA<T> & p_vla)
{
    std::cout << p_name << "\n   MyVla.size() : ["
              << p_vla.size() << "]\n" ;

    for(size_t i = 0, iMax = p_vla.size(); i < iMax; ++i)
    {
        std::cout << "   [" << i << "] : [" << p_vla[i] << "]\n" ;
    }
}

int main()
{
    {
        MY_VLA(vlaInt, 5, int) ;

        outputVLA("vlaInt: Before", vlaInt) ;

        vlaInt[0] = 42 ;
        vlaInt[1] = 23 ;
        vlaInt[2] = 199 ;
        vlaInt[3] = vlaInt[1] ;
        vlaInt[4] = 789 ;

        outputVLA("vlaInt: After", vlaInt) ;
    }

    {
        MY_VLA(vlaString, 4, std::string) ;

        outputVLA("vlaString: Before", vlaString) ;

        vlaString[0] = "Hello World" ;
        vlaString[1] = "Wazaabee" ;
        vlaString[2] = vlaString[1] ;
        vlaString[3] = "Guess Who ?" ;

        outputVLA("vlaString: After", vlaString) ;
    }
}

如您所见,MyVLA对象知道它的大小(这比在C99 VLA上使用sizeof运算符要好得多。)

当然,MyVLA类的行为类似于数组,并且由size_t值初始化(可以在运行时更改)。唯一的故障是由于函数alloca()的性质,这意味着构造函数应该只通过宏MY_VLA间接使用:

下面是该类的代码,在文件MyVLA.hpp

#include <alloca.h>

template <typename T>
class MyVLA
{
    public :
        MyVLA(T * p_pointer, size_t p_size) ;
        ~MyVLA() ;

        size_t          size()                          const ;
        const T &       operator[] (size_t p_index)     const ;
        T &             operator[] (size_t p_index) ;

    private :
        T * m_begin ;
        T * m_end ;
} ;

#define MY_VLA(m_name, m_size, m_type)                                                      \
m_type * m_name_private_pointer = static_cast<m_type *>(alloca(m_size * sizeof(m_type))) ;  \
MyVLA<m_type> m_name(m_name_private_pointer, m_size)

template <typename T>
inline MyVLA<T>::MyVLA(T * p_pointer, size_t p_size)
{
    m_begin = p_pointer ;
    m_end = m_begin + p_size ;

    for(T * p = m_begin; p < m_end; ++p)
    {
        new(p) T() ;
    }
}

template <typename T>
inline MyVLA<T>::~MyVLA()
{
    for(T * p = m_begin; p < m_end; ++p)
    {
        p->~T() ;
    }
}

template <typename T>
inline size_t MyVLA<T>::size() const
{
    return (m_end - m_begin) ;
}

template <typename T>
inline const T & MyVLA<T>::operator[] (size_t p_index) const
{
    return *(m_begin + p_index) ;
}

template <typename T>
inline T & MyVLA<T>::operator[] (size_t p_index)
{
    return *(m_begin + p_index) ;
}

宏是一团糟,可能写得更好。这个类本身可能不是异常安全的,但它可以成为。无论如何,它需要更多代码才能使用(即处理复制/分配,使新/删除私有,尽可能添加const等)。我的猜测是,结束并不能证明我花在它上面的时间。所以它仍将是一个概念验证。

关键是“C ++可以模拟C99 VLA,它甚至可以作为C ++对象数组工作!”,我想我已经成功地证明了这一点。

我让读者复制 - 粘贴 - 编译代码以查看结果(我在Ubuntu 10.04上的g ++ 4.4.3上编译它。

答案 11 :(得分:-1)

在C中,您可以定义要删除的变量名称。你不能用C ++做到这一点。

答案 12 :(得分:-2)

C和C ++之间的主要区别在于C ++是面向对象的,而C是面向函数或面向过程的。面向对象编程范例专注于编写更易读和可维护的程序。它还通过打包一组类似对象或使用组件编程模型的概念来帮助重用代码。它通过使用对象,继承和多态的现实世界概念的概念,帮助以逻辑方式进行思考。应该注意的是,这些特征也存在一些缺点。例如,在程序中使用多态可能会降低该程序的性能。

另一方面,功能和过程编程主要关注动作和事件,编程模型侧重于触发程序代码执行的逻辑断言。