当我要求查看cc的当前版本时,我得到了这个.
$ cc --version
cc (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
Run Code Online (Sandbox Code Playgroud)
我想知道的是使用c89,c90,c99或c11中的哪一个.
除其他事项外,C11还增加了"匿名结构和联盟".
我四处寻找,但无法找到匿名结构和工会何时有用的明确解释.我问,因为我不完全明白它们是什么.我得知它们之后是没有名字的结构或联合,但我总是(必须?)将其视为一个错误,所以我只能设想一个用于命名结构的用法.
C11支持匿名结构,如下所示:
struct Foo
{
struct
{
size_t x, y;
};
};
struct Foo f;
f.x = 17;
f.y = 42;
Run Code Online (Sandbox Code Playgroud)
基本上,这样的成员struct被视为封闭的成员struct或union(如果封闭结构本身是匿名的,则递归地).
C++ 11的理由是什么,还包括匿名结构?当然,它们只是非常有用(主要是在工会内部,以消除标识符的输入struct).但它们似乎是对规范的明显补充(以及已经由许多编译器实现的规范),它们肯定必须经过讨论,至少是为了保持与C11标准的兼容性.那他们为什么不加?
我正在制作自己的 C 编译器,以尝试尽可能多地了解有关 C 的详细信息。我现在正在尝试准确地了解volatile对象是如何工作的。
令人困惑的是,代码中的每个读访问都必须严格执行(C11,6.7.3p7):
具有 volatile 限定类型的对象可能会以实现未知的方式进行修改,或者产生其他未知的副作用。因此,引用此类对象的任何表达式都应严格根据抽象机的规则进行评估,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非受到前面提到的未知因素的修改。134)构成对具有易失性限定类型的对象的访问的是实现-定义。
示例:在 中a = volatile_var - volatile_var;,必须读取 volatile 变量两次,因此编译器无法优化a = 0;
同时,序列点之间的评估顺序未确定(C11,6.5p3):
运算符和操作数的分组由语法指示。除非稍后指定,否则子表达式的副作用和值计算是无序的。
示例:b = (c + d) - (e + f)未指定计算添加的顺序,因为它们是无序的。
但是,对未排序对象的评估会产生副作用(例如volatile),行为未定义(C11,6.5p2):
如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则行为是未定义的。如果表达式的子表达式有多个允许的排序,并且在任何排序中出现此类未排序的副作用,则行为未定义。
x = volatile_var - (volatile_var + volatile_var)这是否意味着像未定义这样的表达式?如果发生这种情况,我的编译器应该发出警告吗?
我尝试看看 CLANG 和 GCC 做了什么。既不抛出错误也不发出警告。输出的 asm 显示变量不是按执行顺序读取的,而是从左到右读取的,如下面的 asm risc-v asm 所示:
const int volatile thingy = 0;
int main()
{
int new_thing = thingy - (thingy + thingy);
return …Run Code Online (Sandbox Code Playgroud) 我目前正在使用gcc 4.6.3.我的理解是gcc默认使用gnu89标准,我想启用最新的C标准C11.我试过了:
[pauldb@pauldb-laptop test ]$ gcc -std=c11 -o test test.c
cc1: error: unrecognised command line option ‘-std=c11’
Run Code Online (Sandbox Code Playgroud)
我替换c11了gnu11,我得到了同样的错误.为gcc启用最新C标准的正确方法是什么?
(注意:我对最新的C标准感兴趣,而不是最新的C++标准.)
C1x已成为ISO/IEC 9899:2011又名C11.
有谁知道2011年4月草案n1570标准中有哪些变化(如果有的话)?
ETA:有从伦敦(2011年3月)的委员会会议记录(其中应包括在n1570)这里,从华盛顿特区(2011年10月)在这里 ; 我想DC分钟中接受的变化列表应涵盖的内容.
我想完全理解C11语言的类型层次结构并以图形方式呈现它(树形图将是完美的).该标准没有提供任何关于这个问题的数字 - 有30个点描述了它们之间的各种类型和关系.我想画它.
我的尝试始于获得ISO/IEC 9899:201x委员会草案N1570并从文件第6.2.5节中提取所有必要的陈述.然后,我开始以树的形式重新安排知识.让我分两步介绍我的工作.
提取的知识(第6.2.5节+指定生产内的点):
signed char,short int,int,long int,long long int;_Bool,unsigned char,unsigned short int,unsigned int,unsigned long int,unsigned long long int;float,double …考虑以下C程序:
int f() { return 9; }
int main() {
int (*h1)(int);
h1 = f; // why is this allowed?
return h1(7);
}
Run Code Online (Sandbox Code Playgroud)
根据C11标准,Sec.6.5.16.1,在简单的指配中,"下列之一应持有",列表中唯一相关的一项如下:
左操作数具有原子,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的那种限定词;
此外,这是一个"约束",这意味着,一致的实现必须报告诊断消息(如果它被违反).
在我看来,在上述程序的赋值中违反了这种约束.赋值的两端都是函数指针.所以问题是,两种功能类型是否兼容?第二节回答了这个问题.6.7.6.3:
对于要兼容的两种函数类型,两者都应指定兼容的返回类型.146)此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用中一致; 相应的参数应具有兼容的类型.如果一个类型具有参数类型列表而另一个类型由函数声明符指定,该函数声明符不是函数定义的一部分并且包含空标识符列表,则参数列表不应具有省略号终止符,并且每个参数的类型应为与应用默认参数促销产生的类型兼容.如果一个类型具有参数类型列表而另一个类型由包含(可能为空)标识符列表的函数定义指定,则两者应在参数数量上一致,并且每个原型参数的类型应与类型兼容这是因为默认参数促销应用于相应标识符的类型.
在这种情况下,h1的类型之一具有参数类型列表; 另一个,f,没有.因此,上述引文中的最后一句适用:特别是"两者应在参数数量上达成一致".显然h1需要一个参数.f怎么样?以下几点出现在上述之前:
函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数.
所以很明显f取0个参数.因此,两种类型的参数数量不一致,两种函数类型不兼容,并且赋值违反约束,应该发出诊断.
但是,编译程序时gcc 4.8和Clang都不会发出警告:
tmp$ gcc-mp-4.8 -std=c11 -Wall tmp4.c
tmp$ cc -std=c11 -Wall tmp4.c
tmp$
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果f被声明为"int f(void)...",两个编译器都会发出警告,但根据我对上述标准的阅读,这不应该是必要的.
问题:
Q1:赋值"h1 = f;" 在上面的程序中违反了约束"两个操作数都指向兼容类型的限定或不合格版本"?特别:
Q2:表达式"h1 = f"中的h1类型是某些函数类型T1的指向T1的指针.究竟什么是T1?
Q3:表达式"h1 = f"中的f类型是某些函数类型T2的指向T2的指针.究竟什么是T2?
问题4:T1和T2兼容吗?(请引用标准或其他文件的相应部分以支持答案.)
Q1',Q2',Q3',Q4':现在假设f的声明改为"int f(void){return 9;}".再次回答问题1-4这个程序.
这个问题遵循前一个关于定义的问题memcpy(0, 0, 0),该问题最终被确定为未定义的行为.
正如相关问题所示,答案取决于C11第7.1.4:1条的内容
除非在以下详细说明中另有明确说明,否则以下每个语句均适用:如果函数的参数具有无效值(例如函数域外的值,或程序地址空间外的指针,或空指针,[...])行为未定义.[...]
标准函数memcpy()需要指向void和const void,如下所示:
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
Run Code Online (Sandbox Code Playgroud)
这个问题值得一问的,只是因为有很多标准的"有效"指针两个概念都:有可以有效地通过指针算术来获得,并且可以有效地相比指针<,>同一对象内部其他指针.并且有一些指针可用于解除引用.前一类包括"一个过去"指针,例如&a + 1和&b + 1下面的代码片段,而后一个类不包括这些指针有效.
char a;
const char b = '7';
memcpy(&a + 1, &b + 1, 0);
Run Code Online (Sandbox Code Playgroud)
如果将上述片段视为已定义的行为,memcpy()则根据void无论如何将参数键入为指针的事实,因此其各自有效性的问题不能解除对它们的解除引用.还是应该&a + 1和&b + 1被认为是"程序的地址空间之外"?
这对我很重要,因为我正在使标准C函数的效果正式化.我写的一个先决条件memcpy()是requires \valid(s1+(0 .. n-1));,直到有人指出我的注意,GCC 4.9已经开始积极优化这样的库函数调用超出了公式中表示上述( …