代码中定义了什么c ++版本?

时间:2017-11-16 19:45:49

标签: c++ c++11 boost-asio

我是C ++的新手。我使用g ++编译了boost / asio示例中的一些代码。

只有在g ++命令行中使用-std=c++14后才能成功。 我当时理解,我可能错了,boost / asio库使用C ++ 14。

然后我尝试添加用于编码和解码base64的代码。

我收到了链接器错误:

  

对base64_decode的未定义引用(std :: __ cxx11:basic .....

我通过错误理解我传递了C ++ 11格式的std:string,并且链接器在接受该格式的参数的函数的文件中找不到引用。

但是,在代码中我可以看到此方法接受哪种格式? 如果我的代码boost / asio有一个std::string并且我将它传递给了这个函数:

std::string base64_decode(std::string const& s)

为什么链接器会通知我此参数是C ++ 11 std::string

这是如何运作的?

在代码中,哪个是使用的C ++版本?

这是我尝试添加的Base64文件:

#ifndef _BASE64_H_
#define _BASE64_H_
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
#endif  

这是cpp文件

#include "base64.h"

static const std::string base64_chars = 
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789+/";


static inline bool is_base64(unsigned char c) {
  return (isalnum(c) || (c == '+') || (c == '/'));
}

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (in_len--) {
    char_array_3[i++] = *(bytes_to_encode++);
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;

      for(i = 0; (i <4) ; i++)
        ret += base64_chars[char_array_4[i]];
      i = 0;
    }
  }

  if (i)
  {
    for(j = i; j < 3; j++)
      char_array_3[j] = '\0';

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;

    for (j = 0; (j < i + 1); j++)
      ret += base64_chars[char_array_4[j]];

    while((i++ < 3))
      ret += '=';

  }

  return ret;

}

std::string base64_decode(std::string const& encoded_string) {
  size_t in_len = encoded_string.size();
  size_t i = 0;
  size_t j = 0;
  int in_ = 0;
  unsigned char char_array_4[4], char_array_3[3];
  std::string ret;

  while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
    char_array_4[i++] = encoded_string[in_]; in_++;
    if (i ==4) {
      for (i = 0; i <4; i++)
        char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));

      char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
      char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

      for (i = 0; (i < 3); i++)
        ret += char_array_3[i];
      i = 0;
    }
  }

  if (i) {
    for (j = i; j <4; j++)
      char_array_4[j] = 0;

    for (j = 0; j <4; j++)
      char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));

    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
    char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
  }

  return ret;
}

2 个答案:

答案 0 :(得分:2)

回答你提出的问题(但可能不是你想要的问题)(&#34;代码中的内容定义了c ++版本? &#34)

实现应该定义__cpluplus宏([cpp.predefined]),它解析为以下值。

  • C ++ 03:199711L
  • C ++ 11:201103L
  • C ++ 14:201402L
  • C ++ 17:201703L

对于每个新标准,此值旨在变大。

也就是说,当您开始链接时,不同的库可能兼容也可能不兼容(ABI兼容),即使对于为__cplusplus定义相同值的编译器版本也是如此。如果您构建一个C ++ 11项目,您应该更喜欢链接同一平台上使用相同编译器编译的库。

不过,这更像是一个案例。您应该查阅您使用的给定库版本的文档。特别提到了release notes中有关编译器兼容性的讨论。 Boost的Windows库还列出了编译器版本(例如,Visual Studio 2015的Boost 1.63在其名称中都有vc140

由于您的错误消息似乎与std::__cxx11相关,因此我们可以推断您使用gcc。他们写了关于您确切问题的this helpful page。 这是最重要的一行:

  

如果您收到有关涉及std::__cxx11命名空间[...]中类型的符号的未定义引用的链接器错误,那么它可能表示您正在尝试将使用不同值编译的目标文件链接在一起_GLIBCXX_USE_CXX11_ABI宏。链接到使用旧版GCC

编译的第三方库时,通常会发生这种情况

关于_GLIBCXX_USE_CXX11_ABI宏的更多信息:

  

在GCC 5.1版本中,libstdc ++引入了一个新的库ABI,其中包括std::stringstd::list的新实现。这些更改必须符合2011 C ++标准,该标准禁止写入时复制字符串并要求列表跟踪其大小...

  _GLIBCXX_USE_CXX11_AB I宏(请参阅宏)控制库头中的声明是使用旧的还是新的ABI。因此,可以针对正在编译的每个源文件单独决定使用哪个ABI。使用GCC的默认配置选项,宏的默认值为1,这会导致新的ABI处于活动状态,因此要使用旧的ABI,必须在包含任何库之前将宏显式定义为0头。

答案 1 :(得分:2)

您遇到的问题是由于C ++ 11将需求更改为std::string(或者更优先 - std::basic_string)而禁止使用libstdc ++先前使用的copy-on-write语义

要采用C ++ 11,libstdc ++必须更改std::basic_string的布局,从而破坏现有的应用程序。为避免这种情况,C ++ 11字符串在内部使用不同的名称。在<bits/basic_string.h>中,您可以找到此宏:

# define _GLIBCXX_BEGIN_NAMESPACE_CXX11 namespace __cxx11 {

<string>中使用。因此,libstdc ++中C ++ std::string的实际名称以std::__cxx11::开头,而不是std::

由于libstdc ++同时提供std::string的C ++ 11和C ++ 98版本,因此您需要确保代码在使用此类时保持一致 - 所有代码和库只应使用一个版本是可互操作的,例如一切都应该用C ++ 98 / C ++ 03或C ++ 11及更新版本构建。简而言之,您必须始终使用编译器的-std=c++11-std=c++14-std=c++17标记。