我只是想知道是否有人知道在互联网上开发状态机的一些很好的教程.还是电子书?
我开始在状态机上工作,只需要一些通用的东西让我开始.
我想知道是否有可能迭代传递给C99中的可变参数宏或使用任何GCC扩展的参数?
例如,是否可以编写一个通用的宏,它接受一个结构,并将其字段作为参数传递,并打印结构中每个字段的偏移量?
像这样的东西:
struct a {
int a;
int b;
int c;
};
/* PRN_STRUCT_OFFSETS will print offset of each of the fields
within structure passed as the first argument.
*/
int main(int argc, char *argv[])
{
PRN_STRUCT_OFFSETS(struct a, a, b, c);
return 0;
}
我写了一个C程序,它接受来自用户的整数输入,用作整数数组的大小,并使用该值声明给定大小的数组,我通过检查数组的大小来确认它.
码:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
int k[n];
printf("%ld",sizeof(k));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
而且令人惊讶的是它是正确的!该程序能够创建所需大小的数组.
但是所有静态内存分配都是在编译时完成的,并且在编译期间,其值n是未知的,那么为什么编译器能够分配所需大小的内存呢?
如果我们能够分配所需的内存就是这样,然后有什么用使用动态分配的malloc()和calloc()?
我想知道是否有任何文件可以设置-std=c99标志,所以我不必为每次编译设置它.我在Ubuntu上使用GCC 4.4.
void func()
实际上,空参数表示接受任何参数.
void func(void) 不接受任何争论.
但在标准C99中,我找到了这样的界限:
6.7.5.3函数声明
符(包括原型) 14标识符列表仅声明函数参数的标识符.函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数.函数声明符中的空列表不是该函数定义的一部分,它指定不提供有关参数数量或类型的信息.
根据标准,func()并且func(void)是相同的?
Stack Overflow问题的一些答案获取浮点数的IEEE单精度位建议使用union类型双关的结构(例如:将a的位float转换为a uint32_t):
union {
float f;
uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
Run Code Online (Sandbox Code Playgroud)
但是,uint32_t根据C99标准(至少草案n1124),联盟成员的值似乎未指定,其中第6.2.6.1.7节规定:
当值存储在union类型的对象的成员中时,对象表示的字节与该成员不对应但与其他成员对应的字节采用未指定的值.
C11 n1570草案至少有一个脚注似乎暗示不再是这种情况(见6.5.2.3中的脚注95):
如果用于读取union对象的内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的适当部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时被称为''punning'').这可能是陷阱表示.
但是,第C.6.6.1.7节中的案文与C11草案中的C99草案相同.
这种行为在C99下实际上是未指定的吗?它是否在C11中指定?我意识到大多数编译器似乎都支持这一点,但是知道它是在标准中指定还是只是一个非常常见的扩展会很好.
这个C99代码是否会产生未定义的行为?
#include <stdio.h>
int main() {
int a[3] = {0, 0, 0};
a[a[0]] = 1;
printf("a[0] = %d\n", a[0]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在声明中a[a[0]] = 1;,a[0]都是读取和修改.
我看了ISO/IEC 9899的n1124草案.它说(在6.5表达式中):
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算来修改一次.此外,先前的值应该只读以确定要存储的值.
它没有提到读取对象来确定要修改的对象本身.因此,此语句可能会产生未定义的行为.
但是,我觉得很奇怪.这实际上是否会产生未定义的行为?
(我也想知道其他ISO C版本中的这个问题.)
考虑这个(可怕的,可怕的,没有好的,非常糟糕的)代码结构:
#define foo(x) // commented out debugging code
// Misformatted to not obscure the point
if (a)
foo(a);
bar(a);
Run Code Online (Sandbox Code Playgroud)
我已经看到两个编译器的预处理器在这段代码上生成不同的结果:
if (a)
bar(a);
Run Code Online (Sandbox Code Playgroud)
和
if (a)
;
bar(a);
Run Code Online (Sandbox Code Playgroud)
显然,对于可移植的代码库来说这是一件坏事.
我的问题:预处理器应该用这个做什么?首先是Elide评论,还是先扩展宏?
我以前认为在C99中,即使函数的副作用f和g干扰,虽然表达式f() + g()不包含序列点,f并且g会包含一些,所以行为将是未指定的:要么f()之前调用f()之前的g()或g().
我不再那么肯定了.如果编译器内联函数(即使未声明函数,编译器可能决定这样做inline)然后重新排序指令,该怎么办?可能有人得到上述两种不同的结果吗?换句话说,这是未定义的行为吗?
这不是因为我打算写这种东西,而是在静态分析器中为这样的语句选择最佳标签.
c c99 undefined-behavior sequence-points unspecified-behavior
这个问题是由Herb Sutter的一篇文章的回复引发的,他在那里解释了MS决定不支持/制作C99编译器,但只是采用了C++(11)标准中的C(99)功能.
一位评论者回答说:
(...)C很重要,值得至少注意一点.
有很多现有的代码是有效的C但不是有效的C++.该代码不太可能被重写(...)
因为我只使用MS C++编程,所以我真的不知道"纯粹的"C,即我没有准备好了解C++的细节 - 我正在使用的语言不在C(99)中,而且我几乎没有一些C99代码在C++编译器中无法正常工作的线索.
请注意,我知道只有C99的restrict关键字对我来说似乎有非常狭窄的应用程序和关于可变长度数组(我不确定它们有多广泛或重要).
此外,我很感兴趣是否存在任何重要的语义差异或陷阱,即C(99)代码将在C++(11)下编译,但使用C++编译器而不是C编译器执行不同的操作.
快速链接:答案中的外部资源: