有没有办法errno
在编译时获得与编码时相关的任何字符串的最大大小(在预处理器时间会更好)?例如上限strlen(strerror(errno))
?
我能想到的最好的是运行一个程序,在每个语言环境中对int范围进行强力搜索,以获取与每个{errno,locale}对关联的字符串,获取其大小,并生成标题在该系统上,然后将其挂钩到例如makefile或autoconf或其他任何东西.我想不出更好的方法,但它似乎是荒谬的:系统的标准库具有内置的信息,如果只是隐含的话.获取这些信息真的没有好办法吗?
好的,我承认C和/或C++标准可能允许在运行时生成的错误字符串,例如特定情况消息(例如,strerror(EINVAL)
给出从errno
最后一次设置时的其他运行时元数据集导出的字符串,或者其他东西) -不知道这是允许的,其实我欢迎这样的实现,但我从来没有听说过一个现有的这这样做,或者有一个给定{不止一个字符串errno
,区域设置}对.
对于上下文,我特别想要的(但我认为这个问题在更广泛的方式中是有价值的,正如评论中讨论的那样)导致这个问题是能够使用与errno
syscall/function中相关联的错误字符串writev
.在我的特定用例中,我使用的是字符串argv
和链接 errno
字符串.这将我的"最坏情况"长度设置为ARG_MAX
+ some max errno string length
+ size of a few other small strings
).
我咨询过的每个*nix文档似乎都表示writev
将(或"可能",这个差异在这种情况下产生的好处)错误输出,如果值的总和溢出则errno
设置为.直觉上,我知道我看到的每一根弦都很短,实际上这不是问题.但我不希望我的代码在某些系统上神秘地无法打印错误,如果这个假设可能是假的.所以我编写了代码来处理这种情况 - 但与此同时,我不希望为通常显然不需要它的平台编译额外的代码.EINVAL
iov_len
SSIZE_MAX
errno
到目前为止,答案和评论的综合输入使我倾向于认为在我的特定用例中,"正确"的解决方案是截断长时间的错误消息 - 但这就是为什么我问我最初的做法:这样的信息也有助于选择缓冲区的大小为strerror_r
/ strerror_s
(*nix/Windows),甚至是否定答案(例如"你不能真正做到这一点")在我看来对其他人的教育有用.
这个问题包含strerror_r
了VxWorks上给出的字符串的答案,但我不觉得将其推广到所有系统.
如果我有一个pty或tty主/从对,如果我只有从节点的文件描述符,我怎么办?或者,换一种说法:我能只如果我有主节点的文件描述符呢?
[编辑]
我理解终端/控制台/ SSH的"典型"关系,其具有用于与人交互的主端,以及在从端上的一个或多个程序(例如,shell及其子进程).我(松散地)找到更不寻常的(/过时的)用例,例如将TTY用于其他类型的数据链接,如PPP.这个问题不是 "我没有得到这个TTY业务"的问题.我问的是("低级"?)"API"的东西:例如,如果你没有访问主FD的话,是否有任何termios/ioctl操作或对tty对的其他编程修改无法实现?
[/编辑]
我想明显的是:
还要别的吗?
我一直在阅读一些手册页并在我的Linux机器上进行试验:人们想要用pty做的基本内容(例如stty columns 78
,等等)似乎在"两端"上工作.但我怀疑只有一个进程持有主端的文件描述符才能做到(特别是因为主从名称二分法暗示了一些单边控制/统治).当然,由于我只是在Linux上进行测试,因此Linux和Unix之间的各种版本/配置之间可能存在行为差异,因此我不想假设我所看到的是可移植的.
(如果有人想知道我为什么想知道)
reptyr
,ptyget
,expect
/ empty
,screen
/ tmux
(/ neercs
?在一个与reptyr
样功能),dtach
/ abduco
,和他们没有打我的简约多功能性的甜点.我正在努力变得更加明智,以便我可以更好地评估现有的解决方案和/或更好地设计我自己的工具来划伤我的特殊痒.假设我正在编写一个程序,我希望它遵循 XDG 基本目录规范来放置其文件(如果设置且非空白,则应用程序foo
用作$XDG_CONFIG_HOME/foo
配置文件的目录,或,或 失败并出现错误如果主目录甚至无法解析)。XDG_CONFIG_HOME
~/.config/foo
对于例如XDG_CONFIG_HOME
设置且非空白但该目录不存在的情况是否有正确/指定的行为?或者如果没有这样的变量并且~/.config
不存在?我的程序是否会尝试创建它?或者该目录的不存在是否被认为是环境/系统部分的错误,并且我的程序应该避免对此执行任何操作(只是错误地保释)?
注意:我不是在问我是否应该创建~/.config/foo
- 显然是的;我问如果~/.config
它不存在,我是否应该创建它自己。
(更迂腐一点:显然某些程序应该创建它们 - 问题是这是否只是系统/桌面/用户的工作来这样做,或者是否有任何程序应该尝试创建相关目录(如果它们不存在)?)
我尝试阅读XDG 基本目录规范,它说当尝试写入其文件时,程序可能会创建必需的目录,但不清楚这是否仅指应用程序中的特定/“个人”子目录XDG 基本目录,或者如果这适用于 XDG 基本目录本身。
PS 通常我很清楚要使用什么标签,但在这里我真的不确定:请编辑这篇文章或提出改进建议以赋予其正确的标签。
为什么原始C语言不支持for循环初始化中的初始声明?
显然,原始创建者,然后是C99之前的标准化,并没有这样指定.但我似乎无法找到为什么做出设计选择的任何理由.
我似乎找到的答案最接近的是这个答案解释了混合声明和代码是如何被禁止的,以便允许编译器在重要时单回.乍一看,有意义的是,for循环语句中的声明与声明与代码混合时会产生相同/类似的问题.
但是,在C99之前的C 块确实支持了块开头的声明:
{
unsigned int i;
for(i = 0; i < WHATEVER; i += 1)
{
/* ... */
}
}
Run Code Online (Sandbox Code Playgroud)
我个人没有看到编译逻辑与此有何不同:
for(unsigned int i = 0; i < WHATEVER; i += 1)
{
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
在我看来,如果编译器可以执行前一次通过,它也可以执行后者.它可能要求一个for
语句总是创建一个范围块(即使后面跟着一个语句而不是一个语句{ ... }
块),但是我想不出这种语义可以打破任何其他前C99 C代码的方法(或者for语句之后是一个块,在这种情况下它已经"作用域",或者后面跟着一个语句,在这种情况下,无论如何都不会在该单个语句中允许新的声明).
那么,为什么这个语法"功能"最初被省略了?我错误地认为在不违反当时的绩效目标的情况下提供支持是微不足道的吗?当时已知的语言解析器/编译器技术是否让它看起来更难?它是否因为极简主义的设计/心态而被省略,因为在功能上它可以做同样的事情(围绕循环)?或者是否存在明确的语言设计原因(例如,Go最初是如何排除异常的,因为设计师认为这是为了更好的语言)?
我想定义一个结构体:
struct error
{
int errno;
/* other information */
};
Run Code Online (Sandbox Code Playgroud)
然后我希望我的代码具有如下所示的错误路径:
struct error my_error;
my_error.errno = errno;
/* set other fields on the error */
Run Code Online (Sandbox Code Playgroud)
但如果相同的翻译单元包含#include <errno.h>
,则errno
通常是一个被其他内容替换的宏。
假设您实际上需要访问errno
该翻译单元,因此您不能只是取消定义它,有没有办法仍然拥有该结构字段名称?
我不在乎它是通过抑制特定令牌的扩展,还是通过某种方式让errno
令牌由其他宏扩展生成,而其他宏扩展不会进一步扩展,或者任何方法。
最终这并不重要,我可以将该字段命名为其他名称,例如error
或error_number
。我只是不喜欢无法给事物命名似乎是最合适的名称。
我很好奇是否有关于在C中进行恒定折叠的任何保证.
在我不知道其声誉的网站上的这个链接发表了一个随意的评论:
所有C编译器都可以折叠宏扩展后存在的整数常量表达式(ANSI C要求).
但我没有看到任何内容,例如C编程语言,第二版(我认为已经彻底更新以解释ANSI C的所有细节).但是在检查了相关单词的引用索引后,我发现没有任何承诺.第38页和第209页特别接近,因为他们说任何可以在编译时评估的表达式都可以用于可以使用常量的地方(如果我们足够迂腐,可能有一些限制),并且它表示这样的表达式" 可能 "在编译时进行评估,而不是"将"/(某些同义词).
我搜索了这个C89最终草案.单词"折叠"和"折叠"没有产生任何有价值的结果,搜索"常量表达"产生了63个匹配,其中我检查了大约一半.感兴趣的主要部分似乎基本上与书相同(它使用" can "而不是"may",但在这种情况下它们是同义词).
这两个似乎在逻辑上强烈暗示我每个ANSI C编译器必须具有基本的常量折叠功能,但同时,似乎没有任何硬性禁止将常量表达式编译成计算表达式的代码在运行时(这样的实现仍然受益于常量表达式,因为编译器可以生成一次计算它的代码然后假设值不会改变,并且这样的实现可能会受到给定底层架构中的限制的强制 - 例如几个RISC架构必须使用两条指令来初始化某些可能的值,或者从内存位置加载它们.
我还简要搜索了这个C99最终草案,但是"折叠"产生了一个没有价值的结果,而"折叠"和"常数"有超过一百个匹配,我目前无法分配时间来爬行.
我在一些比特杂乱的代码中编写了这些宏以获得更多的语义/意图清晰度:
#define UCHAR_LOW_N_BITS_m(n) (unsigned char )(UCHAR_MAX >> (CHAR_BIT - (n)))
#define UCHAR_NTH_BIT_m(n) (unsigned char )(1 << (n))
Run Code Online (Sandbox Code Playgroud)
..where n
总是一个整数字面值.我想要得到安慰,听到一个令人安心的声音说"没关系,所使用的每个C编译器远程重要都会为你折叠这些常量".(PS我问了一个单独的问题,是否UCHAR_NTH_BIT_m
应该表现为从第0位或第1位开始,希望是在正确的位置.)
是的,底部的一个可以变成单独的宏,例如#define UCHAR_1ST_BIT_m (unsigned char )1
通过#define UCHAR_3RD_BIT_m (unsigned char )4
或者我在代码中碰巧需要的许多宏- 虽然我还没有决定哪个更好,但这可能是一个没有实际意义的点,因为如果我想要的话要成为一名优秀的迂腐语言 - 律师型C程序员,我无法完全避开顶级程序员(必须确保代码在那些DSP /嵌入式和古代大型机C实现上做正确的事情).