如何将字符串可移植地转换为不常见的整数类型?

发布于 2024-07-11 12:29:46 字数 1106 浏览 9 评论 0原文

一些背景:例如,如果我想使用 scanf() 将字符串转换为标准整数类型,例如 uint16_t,我会使用 来自 的 SCNu16,如下所示:

#include <stdio.h>
#include <inttypes.h>
uint16_t x;
char *xs = "17";
sscanf(xs, "%" SCNu16, &x);

但是像 pid_t 这样更不常见的整数类型没有任何这样的东西; 仅支持普通整数类型。 要以另一种方式转换,以可移植 printf()pid_t,我可以将其转换为 intmax_t 并使用 PRIdMAX >,像这样:

#include <stdio.h>
#include <inttypes.h>
#include <sys/types.h>
pid_t x = 17;
printf("%" PRIdMAX, (intmax_t)x);

但是,似乎没有办法将 scanf() 移植到 pid_t 中。 所以这是我的问题:如何便携地做到这一点?

#include <stdio.h>
#include <sys/types.h>
pid_t x;
char *xs = 17;
sscanf(xs, "%u", &x);  /* Not portable! pid_t might not be int! /*

我想到 scanf() 转换为 intmax_t,然后检查该值是否在 pid_t 的限制内,然后再转换为 pid_t,但似乎没有办法获取pid_t的最大值或最小值。

Some background: If I wanted to use for, for instance, scanf() to convert a string into a standard integer type, like uint16_t, I’d use SCNu16 from <inttypes.h>, like this:

#include <stdio.h>
#include <inttypes.h>
uint16_t x;
char *xs = "17";
sscanf(xs, "%" SCNu16, &x);

But a more uncommon integer type like pid_t does not have any such thing; only the normal integer types are supported by <inttypes.h>. To convert the other way, to portably printf() a pid_t, I can cast it to intmax_t and use PRIdMAX, like this:

#include <stdio.h>
#include <inttypes.h>
#include <sys/types.h>
pid_t x = 17;
printf("%" PRIdMAX, (intmax_t)x);

However, there does not seem to be a way to portably scanf() into a pid_t. So this is my question: How to do this portably?

#include <stdio.h>
#include <sys/types.h>
pid_t x;
char *xs = 17;
sscanf(xs, "%u", &x);  /* Not portable! pid_t might not be int! /*

I thought of scanf()ing to an intmax_t and then checking that the value is within pid_t’s limits before casting to pid_t, but there does not seem to be a way to get the maximum or minimum values for pid_t.

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

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

发布评论

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

评论(3

笑饮青盏花 2024-07-18 12:29:46

有一种强大且可移植的解决方案,即使用 strtoimax() 并检查溢出。

也就是说,我解析 intmax_t,检查 strtoimax() 中的错误,然后查看它是否“适合”pid_t通过转换它并将其与原始 intmax_t 值进行比较。

#include <inttypes.h>
#include <stdio.h>
#include <iso646.h>
#include <sys/types.h>
char *xs = "17";            /* The string to convert */
intmax_t xmax;
char *tmp;
pid_t x;                    /* Target variable */

errno = 0;
xmax = strtoimax(xs, &tmp, 10);
if(errno != 0 or tmp == xs or *tmp != '\0'
   or xmax != (pid_t)xmax){
  fprintf(stderr, "Bad PID!\n");
} else {
  x = (pid_t)xmax;
  ...
}

不可能使用 scanf(),因为(正如我在评论中所说)scanf() 不会检测溢出。 但我错误地指出,与 strtoll() 相关的函数都没有采用 intmax_tstrtoimax() 可以!

除非您知道整数类型的大小(在本例中为 pid_t),否则使用 strtoimax() 之外的任何内容都不起作用。

There is one robust and portable solution, which is to use strtoimax() and check for overflows.

That is, I parse an intmax_t, check for an error from strtoimax(), and then also see if it "fits" in a pid_t by casting it and comparing it to the original intmax_t value.

#include <inttypes.h>
#include <stdio.h>
#include <iso646.h>
#include <sys/types.h>
char *xs = "17";            /* The string to convert */
intmax_t xmax;
char *tmp;
pid_t x;                    /* Target variable */

errno = 0;
xmax = strtoimax(xs, &tmp, 10);
if(errno != 0 or tmp == xs or *tmp != '\0'
   or xmax != (pid_t)xmax){
  fprintf(stderr, "Bad PID!\n");
} else {
  x = (pid_t)xmax;
  ...
}

It is not possible to use scanf(), because, (as I said in a comment) scanf() will not detect overflows. But I was wrong in saying that none of the strtoll()-related functions takes an intmax_t; strtoimax() does!

It also will not work to use anything else than strtoimax() unless you know the size of your integer type (pid_t, in this case).

泪眸﹌ 2024-07-18 12:29:46

这完全取决于您想要的便携性。 POSIX 表示 pid_t 是有符号整数类型,用于存储进程 ID 和进程组 ID。 在实践中,您可以安全地假设 long 足够大。 否则,您的 intmax_t 必须足够大(因此它将接受任何有效的 pid_t); 问题是,该类型可能接受 pid_t 中不合法的值。 你进退两难。

我会使用 long 并且不太担心它,除了一个 100 年前的软件考古学家会发现和观察的模糊评论,它给出了 256 位 CPU 嘎吱作响的原因当将 512 位值作为 pid_t 传递时。

POSIX 1003.1-2008 现已在网络上提供(全部 3872 页) ,PDF 和 HTML 格式)。 您必须注册(免费)。 我是从 Open Group 书店 找到的。

我所看到的只是它必须是有符号整数类型。 显然,所有有效的有符号整数值都适合 intmax_t。 我在 中找不到任何指示 PID_T_MAX 或 PID_T_MIN 或其他此类值的信息(但我只有这个晚上可以访问它,所以它可能隐藏在我没有寻找它的地方)。 OTOH,我坚持我原来的评论 - 我相信 32 位值在实用上是足够的,无论如何我都会使用 long ,这在 8 位机器上将是 64 位。 我认为可能发生的最糟糕的事情是“适当特权”的进程读取了太大的值,并由于类型不匹配而向错误的进程发送了信号。 我不相信我会为此担心。

...哦!...下的 p400

该实现应支持一个或多个编程环境,其中宽度
blksize_t、pid_t、size_t、ssize_t 和 suseconds_t 的宽度不大于 long 类型的宽度。

It depends on exactly how portable you want to be. POSIX says that pid_t is a signed integer type used to store process IDs and process group IDs. In practice, you could assume with safety that long is big enough. Failing that, your intmax_t must be big enough (so it will accept any valid pid_t); the trouble is, that type could accept values that are not legitimate in pid_t. You're stuck between a rock and a hard place.

I would use long and not worry very much about it except for an obscure comment somewhere that a software archaeologist of 100 years hence will find and observe gives a reason why the 256-bit CPU is creaking to a halt when handed a 512-bit value as a pid_t.

POSIX 1003.1-2008 is now available on the web (all 3872 pages of it, in PDF and HTML). You have to register (free). I got to it from the Open Group Bookstore.

All that I see there is that it must be a signed integer type. Clearly, all valid signed integer values fit into intmax_t. I cannot find any information in <inttypes.h> or <unistd.h> that indicates PID_T_MAX or PID_T_MIN or other such values (but I've only just this evening got access to it, so it could be hidden where I haven't looked for it). OTOH, I stand by my original comment - I believe that 32-bit values are pragmatically adequate, and I would use long anyway, which would be 64-bit on 8-bit machines. I suppose that roughly the worst thing that could happen is that an 'appropriately privileged' process read a value that was too large, and sent a signal to the wrong process because of a mismatch of types. I'm not convinced I'd be worried about that.

...oooh!...p400 under <sys/types.h>

The implementation shall support one or more programming environments in which the widths
of blksize_t, pid_t, size_t, ssize_t, and suseconds_t are no greater than the width of type long.

美人如玉 2024-07-18 12:29:46

如果您确实担心,可以使用 _assert(sizeof(pid_t) <= long) 或您为“%”内容选择的任何类型。

正如这个答案中所解释的< /a>,规范说signed int。 如果 'int' 改变,你的 '%u' 根据定义也会随之改变。

If you are really concerned you can _assert(sizeof(pid_t) <= long) or whatever type you choose for your '%' stuff.

As explained in this answer, the spec says signed int. If 'int' changes, your '%u' by definition changes with it.

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