定义非零整数结构

Posted

技术标签:

【中文标题】定义非零整数结构【英文标题】:Defining a structure of nonzero integers 【发布时间】:2016-03-31 20:23:51 【问题描述】:

假设我们想要定义整数除法以排除除以零。有可能这样做吗?我想要一些看起来像:

#include <stdio.h>
#include <assert.h>

/* Define a structure intn0. */
typedef struct intn0 intn0;

struct intn0
    int x;
    /* assert(x != 0); */
;

int div(int a, intn0 b)
    return a / b.x;
;

显然,这是行不通的。有没有办法在结构级别执行这种断言,比如说,为了定义一个除法函数,以便对于所有有效输入(即正确类型的输入),我们可以保证它会生成一个有效的输出,而无需错误且没有垃圾?

如果你不能在 C 中做到这一点,什么语言会允许这种抽象(最好是类似于 C 而不是 Haskell 之类的东西)?

【问题讨论】:

“排除”是什么意思?预期的行为是什么? 您可能会编写一个函数来返回您的 int,如果输入参数为 0,则返回错误。将其用作初始化函数:int a = init_int(5); 或C++,如果值不为0则抛出异常 你不能“保证它会产生一个有效的输出”,因为结果是不确定的。 @rbaghbanli 我希望输入会引发某种类型错误。我知道这种行为是内置于除法中的,但不难想象我想要这种行为的另一个功能。将它内置到结构中的好处意味着我可以将任意函数链接在一起,而不必担心会引发错误,只要它们的类型正确。这不是为了处理错误。 【参考方案1】:

有没有办法在结构级别上执行这种断言,比如说,

断言对应于(启用时)可执行代码。您不能将断言嵌入到 C 中的数据结构中,尽管您可以在 Java 或 C++ 中(例如)通过将类的成员设为私有并使用测试有效性的代码保护设置它们的所有方法(由类定义) ) 的建议值。正如@RSahu 所观察到的,您可以在 C 中做类似的事情,尽管该语言没有提供实际强制执行它的方法。

但是,在某些情况下,可以定义一个数据结构,它不代表您不希望它表示的值。例如:

/*
 * Represents a non-zero integer between -(UINT_MAX+1) and (UINT_MAX+1),
 * inclusive; has no representation for zero.
 */
struct intn0 
    _Bool is_negative;
    unsigned n_less_one;
;

为了定义一个除法函数,以便对于所有有效输入(即正确类型的输入),我们可以保证它会生成一个没有错误且没有垃圾的有效输出?

上述结构类型的整数除法可能如下所示:

int div(int a, struct intn0 b)
    return (b.is_negative ? -1 : 1) * (a / ((long long) b.n_less_one + 1));
;

假设long long 类型足够大以表示@​​987654324@,它永远不会被零除,并且总是会为每对可能的参数产生一致且合理的结果。如果划分语义不是您想要的,那么我相信您可以调整它们以适应它们。

【讨论】:

我认为您要做的第一件事是定义 ERR_MSG 因为 -1 和 0 都可以是有效商;然后浮点除法(浮点数,浮点数)if(!dem)返回(ERR_MSG);否则返回(数字/数字); @ArifBurhan,这种方法无法将0 表示为除数(这就是重点),但它将-1 作为除数处理就好了。此struct intn0 提供符号/幅度整数表示,其中幅度记录为 unsigned 值,该值比结构对应的整数的绝对值小一。【参考方案2】:

有没有办法在结构层面执行这种断言,

如果你使用不透明的指针,你可以做到这一点。

.h 文件:

// Declare the struct but don't define it in the .h file.
typedef struct intn0 intn0;

intn0* create_intn0(int val);

int get_value(intn0* intPtr);

.c 文件:

#include "***.h" // Use an appropriate name for the .h file.

// Define the struct so that functions in the .c file can use it.
struct intn0  int n; ;

intn0* create_intn0(int val)

   assert(val != 0);
   intn0* intPtr = malloc(sizeof(*intPtr));
   assert(intPtr  != NULL);
   intPtr->n = val;
   return intPtr;


int get_value(intn0* intPtr)

   assert(intPtr != NULL);
   return intPtr->n;

【讨论】:

GCC 在内存分配步骤中给我一个错误消息“'malloc' 的参数 1 的类型不兼容”。 @AndrewSalmon,应该是malloc(sizeof(*intPtr))。我的错。【参考方案3】:

我不认为这是对 C 结构的合理期望(没有它比它的价值更麻烦)。您可能会切换到 C++ 并编写自定义整数类,但您将需要大量代码来实现 int(您是 can't inherit from int)的所有正常行为。

最好的办法是定义一个自定义除法函数:

int zero_safe_div(int a, int b)

    if (b != 0)
        return a / b;
    else
         /* return zero or whatever behavior you want in this case */

由于您似乎对其他语言持开放态度,因此您也可以使用 Python,它允许您从 int 类型继承(因为它只是一个类,就像 Python 中的其他所有内容一样):

class safe_div_int(int):
    def __init__(self, val):
        self.val = val
    def __div__(self, rhv):
        if rhv != 0:
            return self.val / rhv
        else:
            return 0 # this could be replaced with whatever behavior you want for the 
                     # zero division case

v1 = safe_div_int(3)

print("V1: ".format(v1))
print("V1 / 5.0: ".format(v1 / 5.0))
print("V1 + 5: ".format(v1 + 5))
print("V1 / 0: ".format(v1 / 0))

这段代码产生这个输出:

V1:3 V1 / 5.0:0.6 V1 + 5:8 V1 / 0: 0

【讨论】:

以上是关于定义非零整数结构的主要内容,如果未能解决你的问题,请参考以下文章

02-线性结构2 一元多项式的乘法与加法运算

02-线性结构2 一元多项式的乘法与加法运算

02-线性结构2 一元多项式的乘法与加法运算 (20 分)

PTA 02-线性结构2 一元多项式的乘法与加法运算

02-线性结构2 一元多项式的乘法与加法运算 (20 分)

C++ 中结构的构造函数导致非零退出代码