【问题标题】:Variable sized char[] - Is it OK?可变大小的 char[] - 可以吗?
【发布时间】:2011-03-13 21:22:29
【问题描述】:

如果这是愚蠢的,请原谅我,但我是 C/C++ 的新手。

在我正在创建的套接字库中,我的 ClientSocket::recv(int bufsize) 函数使用 'bufsize' 来初始化一个 char[] 数组以从 C 套接字读取。使用 G++ 编译的代码可以正常工作。

我遇到的问题是一些正在编译我的代码的人收到以下错误: socket.cxx||In member function ‘std::string ClientSocket::recv(int)’:| socket.cxx|269|error: ISO C++ forbids variable length array ‘buffer’|

现在,从我在这个论坛上看到的内容来看,Microsoft 只支持 C89,而 GCC 支持 C99,其中可以接受可变大小的数组。同样在那个线程上,他们建议使用 _alloca() - 问题是,它最多只支持 1mb。我宁愿没有限制。

如果这是使它与 GCC/MSVC++ 交叉编译的唯一可能方法,我想我将不得不接受它。很高兴知道一个替代方案。像 malloc() 这样的东西会起作用吗? (以前从未使用过,所以我不知道)如果是这样,你能告诉我如何使用它或链接到教程/文档吗?谢谢!

P.S.:这是我的 recv() 函数的代码:

std::string ClientSocket::recv(int bufsize) {

    // isConnected() is a ClientSocket function
    if (!isConnected()) throw SocketException("Not connected.");

    char buffer[bufsize+1];

    // I did this because sometimes it was returning partial garbage :\
    memset(buffer, 0, bufsize);

    // the :: prefix means to call the recv() from the header files instead of ClientSocket::recv()
    int ret = ::recv(sockfd, buffer, bufsize-1, 0);

    if (ret < 0) {
        switch(errno) {
            case ECONNREFUSED:
                throw SocketException("Connection refused on recover.");
                break;
            case ENOTCONN:
                throw SocketException("Not connected.");
                break;
            default:
                throw SocketException("Unknown error reading socket.");
                break;
        }
    } else if (ret == 0) {
        // we got disconnected, return empty string. (connected is a protected variable of ClientSocket)
        connected = false;
        return "";
    }

    return buffer;
}

编辑:根据建议,我计划使用 vector buffer(bufsize+1, 0); ... recv(sockfd, &amp;buffer[0], bufsize, 0); ... return &amp;buffer[0];char *buffer = new char[bufsize + 1]; memset(buffer, 0, bufsize); ... recv(sockfd, buffer, bufsize, 0); ... string tmp = buffer; delete [] buffer; return string(tmp); - 仍在安装 MSVC++ 以对其进行测试,但我相信它会起作用。太感谢了! StackOverflow 摇滚!

【问题讨论】:

  • 我这里可能有点跑题了,但是你需要超过 1 兆字节的 socket io 缓冲区吗?
  • 好点。通常我使用 1024 字节,但我将把它作为一个库分发,我不喜欢以任何方式限制它。
  • 库的全部意义不在于将行为集中到定义的路径中(这是一种施加限制的形式?)就个人而言,我说合理的限制根本不是问题。开发人员可以非常轻松地绕过合理的限制。如果最终成为问题,他们会告诉你(哦,天哪,天哪,他们会告诉你的!)
  • 您没有收到整个传入缓冲区,并且您正在分配一个字节,但您没有设置那个额外的字节;你可能想写 buffer[ret] = 0;返回缓冲区;而是。
  • @Neil - 谢谢,我会这样做的。 :) @glowcoder - 我真的希望它像 python 的套接字库一样,afaik 对 recv() 没有限制。

标签: c++ arrays variables size iso


【解决方案1】:

g++ 允许 C++ 中的 C99 可变长度数组作为语言扩展。

标准 C++ 不支持它们。

在 C++ 中使用 std::vectorstd::string

干杯,

【讨论】:

  • 但问题是我无法将向量传递给 ::recv(sockfd, buffer, bufsize-1, 0);的 C 插座。 AFAIK,它一定是一个字符 *...如果我错了,请纠正我。
  • @FurryHead:如果(且仅当)您使用std::vector&lt;char&gt; buffer( buffsize + 1, 0 );,您可以拨打recv(sockfd, &amp;buffer[ 0 ], bufsize, 0); 并跳过拨打memset
  • 不会是 std::vector ... 吗? vector 就像一个字符列表,vector 将是一个指向 char[] 的指针列表,不是吗? (但我明白你现在在说什么)这确实很方便,因为不会调用 memset 也不会处理删除内容。谢谢!@
  • @FurryHead: char buffer[] 是一个字符列表,vector&lt;char&gt; 是 C++ stdlib 等价物。
  • 啊。感谢您的澄清,当您输入: std::vector buffer(bufsize+1); recv(sockfd, &buffer[0], bufsize, 0);看来您传递的是 char 而不是 char[]。
【解决方案2】:

尝试这样做:

char * buffer = new char[bufsize + 1];

【讨论】:

  • 这会慢一倍。堆管理器的压力增加了一倍。
  • 我目前没有MSVC++,但我会尽快安装它。
  • @Fyodor,性能影响非常小;我怀疑它是否引人注意。
  • 到底有多慢?相差0.00001ms?还是一秒钟?如果数量少得离谱,我不在乎 - 如果我关心速度,我就不会在 C 套接字之上制作 C++ 包装类;)编辑:谢谢@myrkos,在我看到你的之前输入了我的评论。
  • @Fyodor 1) [需要引用] 2) 即便如此,分配速度……真的非常快!因此,即使您将某些东西做得非常非常快,需要两倍的时间,它仍然......非常非常快!
【解决方案3】:

我会创建一个简单的缓冲区类来包装char * 来处理这个问题。它将使用new 来分配缓冲区。我相信也可以使用vector 并且仍然符合标准。但我不完全确定如何以推荐的方式进行。

【讨论】:

  • 我很乐意使用向量,但是标准 berkley c 套接字库中的 recv() 函数将 char* 作为参数 - 包装类不起作用,不是吗?它必须作为 char* 传递
  • @FurryHead:包装类将有一个函数返回其内部char *。它的工作是在适当的时间管理更新和删除char *。这基本上也是您对vector 所做的事情。将&amp;vec[0] 之类的内容传入recv
  • 啊啊,我明白了。在构造函数中有分配器,返回它的函数是 char*,在析构函数中有 delete 调用?这样做会很有趣。谢谢!
【解决方案4】:

如果你使用 gcc 或 g++,你甚至不需要使用 memset 您实际上可以使用普通聚合将其全部分配为零 在 char 类型上,考虑一下:

char * buffer[bufsize+1] = {0};

这段代码只能在 gcc/g++ 中工作,因为 gcc 允许在堆栈上使用可变大小的数组。

您唯一的其他选择是使用:

char * buffer = new char[bufsize+1];
// and assign it zeros with std::fill
std::fill(buffer, buffer+bufsize+1, 0); 

【讨论】:

  • 如果你使用一个向量,你可以使用 &(*vectorname.begin()) 传递向量
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多