goto
在几个SO讨论中已经对这个声明进行了长时间的讨论(见这个和那个),我当然不想重振那些激烈的辩论.
相反,我想专注于goto
s 的单个用例并讨论它的价值和可能的替代方案.
请考虑以下代码片段,这在(至少我自己的)FSM中很常见:
while (state = next_state()) {
switch (state) {
case foo:
/* handle foo, and finally: */
if (error) goto cleanup;
break;
case bar:
/* handle bar, and finally: */
if (error) goto cleanup;
break;
/* ...other cases... */
}
}
return ok;
cleanup:
/* do some cleanup, i.e. free() local heap requests, adjust global state, and then: */
return error;
Run Code Online (Sandbox Code Playgroud)
在一个单独的函数中交换清理东西只是为了保存goto
s似乎很尴尬.另一方面,我们已经被提出来谴责goto
尽可能使用s.
我的问题:我的代码示例被认为是好风格吗?
如果没有,是否有可行的替代方案?
请坚持上述具体用法goto …
人们经常需要一次一个字节地读取内存,就像在这个天真的memcpy()
实现中一样:
void *memcpy(void *dest, const void *src, size_t n)
{
char *from = (char *)src;
char *to = (char *)dest;
while(n--) *to++ = *from++;
return dest;
}
Run Code Online (Sandbox Code Playgroud)
但是,我有时会看到人们明确使用unsigned char *
而不仅仅是char *
.
当然,char
和unsigned char
可能不相等.但这是否有所作为我是否使用char *
,signed char *
或unsigned char *
当按字节读取/写入内存?
更新:实际上,我完全清楚c=200
可能有不同的值,具体取决于类型c
.我在这里问的是为什么人们有时会使用unsigned char *
而不是仅仅char *
在阅读记忆时,例如为了存储uint32_t
一个char[4]
.
ISO/IEC 9899:TC2(即C99标准),§7.20.3规定:
如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象.
换句话说,malloc(0)可以返回NULL或有效指针,我可能不会取消引用.
这种行为背后的理由是什么?
并且定义malloc(0)导致UB不是更容易吗?
我充分意识到之间的主要差异poll()
和select()
:
select()
仅支持固定数量的文件描述符select()
据说在更多系统上支持poll()
允许对事件类型进行稍微细粒度的控制poll()
实现在某些细节上可能不同但是,它们都以大致相同的方式完成相同的任务.所以:
我们要用poll()
还是select()
?
编辑:我可能会补充一点,我不感兴趣,epoll()
因为可移植性是我关注的问题.此外,libev(ent)
也不是一个选项,因为我问这个问题,因为我正在编写自己的替换库libev(ent)
.
C标准保证int
能够存储每个可能的数组大小.至少,这是我从阅读§6.5.2.1,第1小节(数组下标约束)中理解的内容:
其中一个表达式应具有类型''指向对象类型的指针'',另一个表达式应具有整数类型,结果具有类型''type''.
既然我们将int
s用作数组下标,为什么我们应该用它size_t
来确定数组的大小?
为什么strlen()
回报size_t
什么时候int
就够了?
在C vs C++中的typedef和struct命名空间中,其中一条注释似乎意味着暴露某些注释struct foo
优于使用typedef ...
typedef struct foo foo;
Run Code Online (Sandbox Code Playgroud)
...然后使用foo
而不是struct foo
整个API.
后一种变体有任何缺点吗?
一般来说,UB被认为是必须避免的东西,目前的C标准本身列出了附录J中的不少例子.
但是,在某些情况下,除了牺牲可移植性之外,我认为开发UB没有任何害处.
考虑以下定义:
int a = INT_MAX + 1;
Run Code Online (Sandbox Code Playgroud)
评估此表达式会导致UB.但是,如果我的程序打算在32位CPU上运行,模块化算术代表二进制补码中的值,我倾向于相信我可以预测结果.
在我看来,UB有时只是C标准告诉我的方式:"我希望你知道你在做什么,因为我们无法保证会发生什么."
因此我的问题是:即使C标准认为它可以调用UB,或者"UB"真的要避免,无论情况如何,有时依赖依赖于机器的行为是否安全?
我的C标头通常类似于以下样式,以避免多重包含:
#ifndef <FILENAME>_H
#define <FILENAME>_H
// define public data structures / prototypes, macros etc.
#endif /* !<FILENAME>_H */
Run Code Online (Sandbox Code Playgroud)
但是,在他的C语言编程中,Rob Pike对头文件做了如下论证:
有一个小小的舞蹈涉及
#ifdef
到可以防止文件被读取两次,但它在实践中通常是错误的 -#ifdef
它们在文件本身,而不是包含它的文件.结果往往是成千上万的不必要的代码行通过词法分析器,这是(在良好的编译器中)最昂贵的阶段.
一方面,派克是我唯一真正钦佩的程序员.另一方面,将多个#ifdef
s放在多个源文件中而不是将其#ifdef
放在单个头文件中会感到不必要的尴尬.
处理多重包含问题的最佳方法是什么?
线程感知和线程安全之间有什么区别?
language-agnostic concurrency multithreading thread-safety reentrancy
c ×9
coding-style ×4
c++ ×3
char ×1
concurrency ×1
gcc ×1
goto ×1
header-files ×1
int ×1
malloc ×1
networking ×1
posix ×1
reentrancy ×1
size-t ×1
standards ×1