有没有办法在 C++ 编译时限制数据大小并产生编译错误?

Posted

技术标签:

【中文标题】有没有办法在 C++ 编译时限制数据大小并产生编译错误?【英文标题】:Is there a way to limit data size at C++ compile time and produce a compile error? 【发布时间】:2019-03-30 10:12:06 【问题描述】:

我已经构建了一个工具,使学生能够在线(在受保护的环境中)编译和测试他们自己的 C++ 代码。

我想在编译时检查程序中的总数据量是否不超过一定大小,如果超过则产生编译错误。

(直接目标:限制 c++ std::array 大小)

我没有在网上找到信息。

我的编译链是:

g++ -Wall -Wextra -Waddress -std=c++11 -lm -fstack-protector -lm -o exename srcname

感谢您的帮助。

编辑 1

我给他们一个骨架,他们必须完成(此处)指定的位置:

“用‘produitTableau’的定义完成程序(这里),它得到一个整数和一个整数的二维数组,并将‘calcul’函数应用于它的每个值并返回修改后的数组。” (法语...)

#include <iostream>
#include <array>
using namespace std;

const int NB = 3;

int calcul (int a, int b);
array<array<int, NB>,NB> produitTableau(array<array<int, NB>,NB> t, int a);

int main()

    /* déclaration et initialisation  */
    array<array<int, NB>,NB> tab ;
    int x;
    cin >> x;
    for (int i=0;i<NB;i++) for(int j=0; j<NB; j++) cin >> tab[i][j];

    /* traitement et résultat  */
    tab = produitTableau(tab, x);

    /* résultat */
    for (int i=0; i < NB; i++) 
      for (int j=0; j < NB; j++) 
        cout << tab[i][j] << " ";
      
    

  return 0;


int calcul(int a, int b)

   return a*b;


**(here)**

我希望他们写出类似的东西(我使用存储在文本文件中并用作输入数据的测试数据集检查结果):

array<array<int, NB>,NB> produitTableau(array<array<int, NB>,NB> t, int a)

    for (int i=0; i < NB; i++) 
      for (int j=0; j < NB; j++) 
        t[i][j] = calcul(t[i][j] , a);
      
    

   return t;


* 数组是按值传递的 *

所以我会检查使用的数据总量是否超过某个值,例如:10.000 字节。

可能是exe文件...我不知道。

【问题讨论】:

但是您到底想限制什么样的数据?取决于提到的std::array 的使用方式,它会落在.bss、堆栈或堆中 - 取决于您的学生决定如何使用它。您必须限制所有这些(以及可能的 .data)。 你必须比这更具体一点,看起来你在一些细节上有点糊涂;你到底想用你的限制来实现什么?这可能是 X/Y 情况(即您可能在这里尝试解决错误的问题) 你能限制受保护环境的内存吗? “受保护的环境”不是正确的术语:它受到保护,因为学生需要一个 ID 和密码...... 我找到了一个编译选项,如果对象的 siez 大于 x 时会发出警告:“...警告:'t2' 的大小为 4000000 字节 [-Wlarger-than=] |”。这可能是解决方案。但是把警告变成错误?但这不是使用的数组总数... 【参考方案1】:

好吧,如果您阻止包含其他任何内容,您可以调整 std::array&lt;T, N&gt; 以便将 N 限制为某个最大大小;然后让学生包含该数组。

适应可能就像添加一样简单:

static_assert(N == NB, "For this homework assignment you can only use arrays of NB elements");

在数组类中,在文件的前面,

constexpr const size_t NB = 123;

当然切记不要更改原始数组文件!制作一个副本(甚至可以更改名称以说明它是一个自定义数组)。

【讨论】:

这可能是一个解决方案:每个作业都需要一个班级。但是多维数组(例如矩阵)呢? @PatrickDezecache:那会有所不同。但请记住,标准库没有矩阵/张量容器。 作为矩阵,我的意思是二维数组,每个维度都有自己的值,并不总是方阵。 @PatrickDezecache:是的,我意识到这一点,但这与您提出的问题不同。一般来说,我会说 - 选择你喜欢的矩阵的任何实现,制作一个副本,并限制它的尺寸 - 无论是静态的还是动态的。【参考方案2】:

我将实施到部分:

    检查源源固定的约束 使用编译器选项检查大小限制

# 1. 检查源源固定的约束 #

来自@einpoklum 的建议,

## 1.1 将“array”头文件复制到“myArray”并添加“assert”##

...
namespace std _GLIBCXX_VISIBILITY(default)

_GLIBCXX_BEGIN_NAMESPACE_VERSION

template<typename _Tp, std::size_t _Nm>
    struct array
    
       typedef _Tp                        value_type;
      ...
       typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;

       // Support for zero-sized arrays mandatory.
       value_type _M_instance[_Nm ? _Nm : 1];

       static_assert(_Nm == NB, "Check array size...");  <<<<<<<<<<<<

  ... continue...

## 1.2 在主程序中定义数组大小##

const unsigned int NB = 10;  <<<<<<<<<<<<<<<<<<<<<<<<w
#include <iostream>
#include "myArray.h" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
...

示例 1:

const unsigned int NB = 10;
...
#include "myArray.h"
...
int main()

    array<int, 11> tab;
    ...

在编译时:错误:静态断言失败:检查数组大小...

# 2. 使用编译器选项检查大小限制 #

使用编译器选项来强制控制(限制误用的风险:例如 C 数组,或数组的多重定义,...

g++ 编译器选项:

    -Wlarger-than=x : 检查对象的大小(以字节为单位)

    -Wframe-larger-than=x : 检查函数的大小 [https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options][1] -Wframe-larger-than=byte-size

    -Werror : 将警告转为错误

示例 1:(-Wlarger-than=10000)

const int NB = 100;
...
array<array<int, NB>,NB> tab ;

产生错误:...错误:'tab' 的大小为 40000 字节 [-Werror=larger-than=]|

示例 2:(简化示例)(-Wframe-larger-than=10000)

int main()

    array<array<int, 100>,100> tab ;
    int x;
    ...
    tab = produitTableau(tab, x);

    return 0;


array<array<int, 100>,100> produitTableau(array<array<int, 100>,100> t, int a)

...
   return t;

产生错误:...错误:80016 字节的帧大小大于 10000 字节 [-Werror=frame-larger-than=]|

80016 字节 = 制表符 10000*4=40000 字节 + 按值传递的参数 = 40000 字节 + 其他变量...

【讨论】:

以上是关于有没有办法在 C++ 编译时限制数据大小并产生编译错误?的主要内容,如果未能解决你的问题,请参考以下文章

我们的程序能否在编译时确定它在哪个编译器中编译? [复制]

有没有办法将 c++ 编译器标志设为默认值

c++数据对齐/成员顺序&继承

在Qt(或者C++)中,有没有办法得到一个类的变量的名字?

c++中的快速编译

有没有办法在 C++ 编译器中禁用复制省略