当我尝试使用双链接列表实施BigInt时,我应该如何定义BigInt?

发布于 2025-01-22 18:43:25 字数 487 浏览 3 评论 0原文

我正在尝试实施Bigint基本操作,但是在此之前,我需要定义BigInt,以便我可以称呼函数和BigInt A之类的功能。我认为这应该是一个指针,因为然后我可以指向与BigInt关联的列表,但是我不确定100%确定如何定义它以及是否应该是指针。

我有这样的事情:

typedef  *BigInt;

我想称之为这样的东西,

BigInt big_new(char *num);
BigInt sum_b(BigInt a, BigInt b);
BigInt sub_b(BigInt a, BigInt b);
BigInt mult_b(BigInt a, BigInt b);
BigInt div_b(BigInt a, BigInt b);
BigInt mod_b(BigInt a, BigInt b);
void print_b(BigInt a);

我现在在其他文件上实现了列表节点会我的一个整数算法

I am trying to implement the BigInts basic operations but before that I need to define BigInt so I could call functions and things like BigInt a. I think it should be a pointer because I can then point to the list associated with the BigInt, but I am not 100% sure how to define it and if indeed should be a pointer.

I have it like this:

typedef  *BigInt;

And I want to call things like this

BigInt big_new(char *num);
BigInt sum_b(BigInt a, BigInt b);
BigInt sub_b(BigInt a, BigInt b);
BigInt mult_b(BigInt a, BigInt b);
BigInt div_b(BigInt a, BigInt b);
BigInt mod_b(BigInt a, BigInt b);
void print_b(BigInt a);

I have the list implement on other file now I am going to use them to create the big ints I would like create list and a big int will be a list that in one node will me one algorithm of the integer

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

菊凝晚露 2025-01-29 18:43:25

如果您现有的链接列表类型是某种结构(例如typedef struct {...} mylinkedlisttype;,唯一的typeDef,它可以与您的API一起使用,并允许您修改呼叫者的副本(即使没有指针在某些情况下,但并非总是如此)是:

typedef MyLinkedListType *BigInt;  // BigInt is always a pointer to a linked list

这里的主要成本是您无法堆叠分配类型或更精确,您不应该,因为知道是否在堆栈上指向的问题,可以丢弃,或者可以释放,并且必须释放,并且必须与二进制背面一起释放compat问题; > struct 其背后是透明的;仅用动态分配基础结构的API制造和破坏它们。

除此之外:如果您使用typedef -ED指针解决方案,mylinkedlisttype应该是不透明;呼叫者应该永远不要使用bigint除了将其作为函数参数传递(通常是您的API,而对于所有其他功能),而对于他们来说,它只是让他们假设所有权和/或对API的呼叫)。您永远不会看到不是从API中删除指针,将其释放,释放它或做任何没有由您介导的任何东西的代码。一旦指针变得相关, ever ,代码就会令人困惑。它应该是不透明的手柄,或者应明确处理指针(或缺乏指针),而不是隐藏在typedef中。

如果不需要修改呼叫者(例如,所有此类链接列表都指向至少一个节点,并且您将突变该节点的值而不是替换该节点,因此即使是现场操作,也不需要更改什么呼叫者指向),您可以做:

typedef MyLinkedListType BigInt;  // BigInt *is* a linked list

以每个调用上的struct的复制struct,每个呼叫上的mylinkedlistType (删除您直接修改呼叫者的副本的能力;仅修改它指向的内容)。

最后一个选项是“邪恶魔术”选项(但仍在GMP之类的大名库中),其中:

  1. 您可以在将其传递给函数时堆叠分配
  2. ,您隐含地将指针传递给数据,而不是副本(排序 解决方案的类似于C ++参考语义)

是:

typedef MyLinkedListType BigInt[1];

因为它是一个数组,它的大多数用途是指向其第一个(和唯一的)元素指示,因此您可以将其声明为本地函数(并且它具有数据本身的堆栈空间)但是,将其传递给任何其他功能时,它会收到指向该存储的指针(相当于传递& localvar [0])。

许多C程序员讨厌这种方法(隐式参考语义通常不是c; 在这里查看我如何工作),并且不允许逐个价值工作,但就像我说的那样,它是GMP这样的主要库中公认的一部分(实际上是由标准授权的<<代码> JMP_BUF setJMP/longjmp支持中使用的结构),因此不仅合法,而且显然是可用的。就是说,您不会使用:

BigInt big_new(char *num);

在这样的设计中;相反,您将使用:

void big_init(BigInt bi, const char *num);  // Maybe a return code to indicate if an allocation failed or the like

初始化分配的呼叫者变量(例如bigint mynum; big_init(bi,“ 12345”); code_usis_bi; big_clear(bi);)。

像使用指针解决方案一样,单元素阵列解决方案仅应用于逻辑上不透明类型(它们实际上不能是不透明的,因为呼叫者必须能够声明该类型的非分量版本,但是呼叫者绝不应想要/需要修改它们而不经过API)。

您提供的细节有限,这就是我可以给您的。据我所知,指针最适合您现有的API,但是其他方法可能会更好地工作(进行较小的API修改)。

If your existing linked list type is a struct of some sort (e.g. typedef struct { ... } MyLinkedListType;, the only typedef that would work with your APIs as written, and allow you to modify the caller's copy (might be possible even without pointers in some cases, but not always) would be:

typedef MyLinkedListType *BigInt;  // BigInt is always a pointer to a linked list

The main cost here is you can't stack allocate the type. Or more precisely, you shouldn't, due to problems involved in knowing whether what is pointed to is on the stack, and can just be dropped, or on the heap, and must be freed, along with binary back-compat issues; OpenSSL's BIGNUM used to allow both, but eventually decided the benefit of avoiding an allocation in the stack case wasn't worth the costs of knowing which type you had, and the requirement that the struct behind it be transparent; in newer versions, the struct is opaque (user's can't inadvertently rely on a given layout that breaks when the dynamically linked OpenSSL is upgraded) and you can only make and destroy them with APIs that dynamically allocate the underlying struct.

Beyond that: If you use the typedef-ed pointer solution, MyLinkedListType should be opaque; the caller should never do anything with BigInt beyond passing it as a function argument (usually to your APIs, and for all other functions, it would just be for them to assume ownership and/or factor out calls to your APIs). You should never see code that's not from your API dereferencing the pointer, allocating it, freeing it, or doing anything with it that's not mediated by you. As soon as the fact that it's a pointer becomes relevant, ever, the code is confusing; it should either be an opaque handle, or the pointerness (or lack thereof) should be handled explicitly, not hidden in a typedef.

If modifying the caller isn't needed (e.g. all such linked lists point to at least one node and you'd mutate the value of that node rather than replacing it, so even mutate-in-place operations don't need to change what the caller points to), you could do:

typedef MyLinkedListType BigInt;  // BigInt *is* a linked list

at the expense of copying whatever struct makes up MyLinkedListType on each call (removing your ability to modify the caller's copy directly; you could only modify things it points to).

The last option is the "evil magic" option (but still used in big name libraries like GMP), where:

  1. You can stack allocate
  2. When you pass it to a function, you implicitly pass a pointer to the data, not a copy (sort of like C++ reference semantics)

That solution is:

typedef MyLinkedListType BigInt[1];

Because it's an array, most uses of it decay to pointers to its first (and only) element, so you can declare it as a function local (and it gets stack space for the data itself) but on passing it to any other function it receives a pointer to that storage (equivalent to passing &localvar[0]).

Many C programmers hate this approach (implicit reference semantics aren't normally a thing in C; see comments here where I explained how it works), and it doesn't allow pass-by-value to work, but like I said, it's an accepted part of major libraries like GMP (and it's actually mandated by the standard for the jmp_buf struct used in setjmp/longjmp support), so it's not just legal, it's clearly usable. That said, you wouldn't use:

BigInt big_new(char *num);

in such a design; instead you'd use:

void big_init(BigInt bi, const char *num);  // Maybe a return code to indicate if an allocation failed or the like

to initialize a caller variable allocated in-place (e.g. BigInt mynum; big_init(bi, "12345"); code_using_bi; big_clear(bi);).

Like with the pointer solution, the one-element array solution should only be used for logically opaque types (they can't actually be opaque since the caller has to be able to declare non-pointer versions of the type, but the caller should never want/need to modify them without going through your APIs).

With the limited details you provide, that's all I can give you. A pointer fits your existing API best as far as I can tell, but it's possible the other approaches might work better (with minor API modifications).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文