当我查看有关GCC 8的新闻时,我看到他们增加了对2017版C语言的支持(不是C++ 17,真的是C17).但我在互联网上找不到任何关于它的信息.
它是像C11这样的新ISO版本,还是GCC团队用于编译器中某些更正的代号?
C 中的定义是否int a = 0, b = a++, c = a++;定义了行为?
或者几乎等价地,对象定义中的逗号是否像表达式中的逗号运算符一样引入序列点?
对于 C++ 也提出了类似的问题:
C++ 被广泛接受的答案是“是”,它在 C++11 标准第 8/3 段中有完整定义:
声明中的每个初始化声明符都会被单独分析,就像它本身在声明中一样
尽管本段仅涉及语法分析阶段,对于运行时的操作顺序还不够精确。
C语言的情况如何?C 标准是否定义了行为?
之前也有人问过类似的问题:
然而,答案似乎专门针对 C11 草案,并且可能不适用于 C 标准的最新版本,因为自 C11 草案以来,信息性附录 C 的措辞已发生变化,并且似乎也不与标准文本完全一致。
编辑:当然这样的初始化器似乎毫无用处地扭曲。我绝对不会容忍这样的编程风格和结构。这个问题源于关于一个琐碎定义的讨论:int res = 0, a = res;行为似乎没有完全定义(!)。具有副作用的初始化器并不少见,例如考虑以下一个:int arg1 = pop(), arg2 = pop();
在遇到问题" 为什么这些构造使用前后增量未定义的行为? "之后,我决定抓住最新的草案,为我能找到的下一个C标准,并阅读更多相关内容.
在我在C17草案中发现以下段落后不久:
表达式是操作符和操作数的序列,其指定值的计算,或指定对象或函数,或者生成副作用,或执行其组合.在运算符结果的值计算之前对运算符的操作数的值计算进行排序
来源:ISO/IEC 9899:2017,第6.5.1节"表达式"
现在我有点困惑.这i = i++是不是意味着定义了行为?我这次看了另一个草案,C99:
表达式是操作符和操作数的序列,其指定值的计算,或指定对象或函数,或者生成副作用,或执行其组合.
资料来源:ISO/IEC 9899:1999,第6.5.1节"表达式"
它错过了那句话!
以下代码尝试在两个不同的常量上下文中对字符串文字使用数组索引:
static char x = "abcx"[3];
_Static_assert ("abcx"[3] == 'x', "...");
Run Code Online (Sandbox Code Playgroud)
根据Compiler Explorer的判断,工具供应商之间存在明确的共识,即不允许在第二种情况下执行此操作,因为第二种情况明确要求使用整数常量表达式。但是,它们似乎在第一个上下文方面有所不同,第一个上下文只是初始化程序中使用的算术常数表达式。GCC和Clang是允许这样做的实现而脱颖而出。
就其本身而言,这并不有趣,因为在6.6的第10段中,C11 / C18确实表示“实现可以接受其他形式的常量表达式”。但是,在这种情况下脱颖而出是因为:
GCC和Clang都默默地接受了这一点-pedantic(是的,编译器签发并不意味着代码符合要求)。构建代码很有意义,因为它的含义很简单,但是如果他们认为这不符合要求,我会期望发出警告,并且他们可以识别(他们认为)它是否符合要求,因为...
对于这两个编译器,行为最近都发生了变化 -Clang一直在此之前引发错误,直到3.8,而GCC之前一直在引发错误直到8.0。这些版本分别于2016年和2018年发布。这表明更改是有意的,但我还没有找到详细介绍这两个编译器的发行说明。
行为改变的时机使它看起来像与C18有关,但是6.6的措词似乎没有改变。对整数常量表达式的限制仍然严格(如第二行继续显示错误),第9段的措词似乎与C11中的相同,特别是继续说:“对象的值不应为C。通过使用这些运算符可以访问”(wrt []和朋友)。
通过阅读标准,第一个上下文是否是有效的初始化常量(不包括第10段)?我在哪里可能找到GCC / Clang变更的理由?
在C17标准不赞成ATOMIC_VAR_INIT从stdatomic.h,还意味着它支持它,但宁愿它不会被使用.在C17中初始化原子的正确非弃用方法是什么?
与非原子类型相同:
atomic_int foo = 42;
Run Code Online (Sandbox Code Playgroud)
还是新的东西?
具有灵活数组成员的结构是一种可以声明变量并sizeof可以应用变量的类型,这一事实会导致以下程序中出现异常行为。
文件fam1.c:
#include <stdio.h>\n#include <stddef.h>\n\nstruct s {\n char c;\n char t[]; };\n\nextern struct s x;\n\nsize_t s_of_x(void);\n\nint main(void) {\n printf("size of x: %zu\\n", sizeof x);\n printf("size of x: %zu\\n", s_of_x());\n}\nRun Code Online (Sandbox Code Playgroud)\n文件fam2.c:
#include <stddef.h>\n\nstruct s {\n char c;\n char t[2]; };\n\nstruct s x;\n\nsize_t s_of_x(void) {\n return sizeof x;\n}\nRun Code Online (Sandbox Code Playgroud)\n该程序在编译和运行时会发出一些令人惊讶的输出:
\n#include <stdio.h>\n#include <stddef.h>\n\nstruct s {\n char c;\n char t[]; };\n\nextern struct s x;\n\nsize_t s_of_x(void);\n\nint main(void) {\n printf("size of x: %zu\\n", sizeof …Run Code Online (Sandbox Code Playgroud) 在 C11 [C11_N1570]和 C17 [C17_N2176]的最新草案中,我找不到以下内容的证明(我相信这是众所周知的):
sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
有人可以向我推荐特定部分吗?
我知道C++11 的这个回复。回复的第二部分讨论了C,但只涉及了values的范围。它并不能证明字体大小之间的比例。
下面的程序编译没有错误。
#include <stdio.h>
char addr_a[8];
char addr_b[8];
unsigned long my_addr = (unsigned long)addr_b - 8; // PASS
// unsigned long my_addr = (unsigned long)addr_b - (unsigned long)addr_a; // FAIL (error: initializer element is not constant)
int main() {
printf("%lx\n", my_addr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,当我设置时,unsigned long my_addr = (unsigned long)addr_b - (unsigned long)addr_a编译器会抛出“错误:初始化器元素不是常量”。
我知道全局变量只能用常量表达式初始化。我还知道可以在全局初始化程序中使用的常量表达式的类型在C 标准的 6.6p7 节中指定:
初始值设定项中的常量表达式允许有更多的自由度。这样的常量表达式应为以下之一或计算结果为以下之一:
- 算术常量表达式,
- 空指针常量,
- 地址常量,或
- 完整对象类型的地址常量加上或减去整型常量表达式。
请注意,允许地址常量减去整数常量,但不允许地址常量减去另一个地址常量。
问题:
为什么 C 标准限制初始化全局变量的方式?是什么阻止了 C 标准的接受unsigned long my_addr = (unsigned long)addr_b - (unsigned …
为什么不是所有标准头都以std前缀开头?即为什么complex.h而不是stdcomplex.h?
在C ++中,建议使用lock_guard,因为它可以确保在销毁对象时将互斥体解锁。
有没有办法在C中实现相同的功能?还是我们必须手动实现它:
锁定互斥
在全局变量上做某事
解锁互斥锁
#include <stdio.h>
#include <threads.h>
long long x = 0;
mtx_t m;
static void do1() {
mtx_lock(&m);
for(int i = 0; i < 100; i++){
x = x +1;
}
mtx_unlock(&m);
}
static void do2() {
mtx_lock(&m);
x = x / 3;
mtx_unlock(&m);
}
int main(int argc, char *argv[])
{
mtx_init(&m, mtx_plain);
thrd_t thr1;
thrd_t thr2;
thrd_create(&thr1, do1, 0);
thrd_create(&thr2, do2, 0);
thrd_join(&thr2, 0);
thrd_join(&thr1, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)