我想知道是否有任何编译器支持相当数量的新C11标准.寻找像Generic Selection等功能.
有什么建议?
我试图破译导致C99和C11之间发生变化的注释.该说明中提出的修改最终以C11的6.2.4:8结束,即:
具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(包括,递归地,所有包含的结构和联合的成员)是指具有自动存储持续时间和临时生存期的对象.它的生命周期在评估表达式时开始,其初始值是表达式的值.当包含完整表达式或完整声明符的评估结束时,它的生命周期结束.任何使用临时生命周期修改对象的尝试都会导致未定义的行为.
我理解为什么需要进行更改(这里可以进行一些讨论.请注意,讨论可以追溯到C11之前).然而,我不明白的是克拉克·尼尔森写下他的笔记时所说的一句话:
请注意,此方法另外声明了一个这样的示例,它符合C99,是不符合要求的:
struct X { int a[5]; } f();
int *p = f().a;
printf("%p\n", p);
Run Code Online (Sandbox Code Playgroud)
我理解为什么这个例子在C11下是不符合的.我特别不明白的是它是如何符合C99的.并且,如果它是在C99下定义的,它应该做什么,定义打印悬空指针的值?
C11和C++ 11都引入了uchar.h/ cucharheader定义char16_t和char32_t明确的16和32位宽字符,添加了文字语法,u""并U""用于编写具有这些字符类型的字符串,以及宏,__STDC_UTF_16__并__STDC_UTF_32__告诉您它们是否对应于UTF-16和UTF-32代码单元.这有助于消除wchar_t在一些平台上16位且通常用于保存UTF-16代码单元的模糊性,并且在某些平台上是32位并且通常用于保存UTF-32代码单元; 假设现在设置了这些宏,您现在可以编写引用UTF-16和UTF-32的可移植,明确的代码.__STDC_ISO_10646__也可以用作代理来确定是否wchar_t能够保持UTF-32值; 如果它不能,你不一定会认为它拥有UTF-16,但它可能是一个足够近似的便携式.
他们还增加了功能mbrtoc16,mbrtoc32,c16rtomb,并c32rtomb为多字节字符和这些类型之间的转换.在这些和现有mbstowcs的函数系列之间,可以在UTF-16,UTF-32,平台多字节字符集和平台宽字符集之间进行可移植的转换(尽管不一定是无损的,除非平台定义了多字节和宽字符集是UTF;特别是,似乎这些函数在Windows上相当无用,其中语言环境定义的多字节编码不允许每个字符使用两个以上的字节).
此外,他们还添加了u8""编写文字UTF-8编码字符串的语法.由于UTF-8的编码是与经营的大部分功能兼容char *和std::string,这是最有用的新增加的一个.
但是,它们似乎未能添加任何方式来在UTF-8,UTF-16和UTF-32之间进行可移植转换.的mbtoc16实现中定义多字节编码和UTF-16或32之间,并且相关的功能转换; 但你不能依赖这是UTF-8.在类Unix的平台上,它依赖于语言环境,并且其中许多默认情况下在其语言环境中使用UTF-8,即使它不是默认语言,您至少可以将语言环境设置为UTF-8语言环境以便知道"多字节"表示UTF-8.但是,在Windows上,您明确不能使用UTF-8或任何其他需要超过两个字节的编码.
我只是遗漏了一些东西,或者是UTF-8字符串类型没有任何方式将其转换为其他类型的字符串:平台定义的多字节,平台定义的宽字符,UTF-16或UTF-32?甚至无法判断您的系统多字节编码是否为UTF-8?是否有任何理由不包括这种支持(具体来说,我正在寻找C或C++标准委员会的实际书面理由或讨论,而不仅仅是猜测)?是否有任何工作要改善这种情况; 是否有可能在未来改善?
或者,是目前最好的解决办法,如果你想支持UTF-8在便携时尚,写自己的实现,拉库的依赖,或使用特定于平台的功能,如iconv和MultiByteToWideChar?
从1999版开始,ISO C标准定义了一个标准头<stdint.h>,其中定义了typedef intmax_t和uintmax_t.它们分别指定"能够表示任何(有符号|无符号)整数类型的任何值的(有符号|无符号)整数类型".
例如,如果像典型的是,最宽的符号和无符号整数类型是long long int和unsigned long long int,这两者通常是64位,则intmax_t和uintmax_t在可能被定义<stdint.h>如下:
typedef long long int intmax_t;
typedef unsigned long long int uintmax_t;
Run Code Online (Sandbox Code Playgroud)
有一组预定义的有限符号和无符号整数类型,从的signed,unsigned和普通char高达signed和unsigned long long int.
C99和C11还允许实现定义扩展的整数类型,这些类型不同于任何标准类型,并且具有实现定义的关键字的名称.
gcc和clang在某些但不是所有目标上都支持类型__int128和unsigned __int128.这些行为类似于128位整数类型,但它们不被视为扩展整数类型,并且两个编译器的文档都声明它们不支持任何扩展整数类型.因为这些都不是整数类型的标准定义的术语,该类型定义intmax_t和uintmax_t是64位类型的,而不是128位的类型.
这些都不违反C标准(实现不需要具有任何扩展的整数类型,并且只要它们不破坏任何严格符合的程序,它们就被允许具有任意扩展).但在我看来,它将使完美感__int128和unsigned __int128被视为扩展整数类型,以及intmax_t和uintmax_t为128位的类型. …
(通过部分初始化,我的意思是定义为未初始化,其中一个成员设置为某个有效值,但不是全部.并且本地我的意思是使用自动存储持续时间定义.这个问题只讨论那些.)
使用可以使用register定义的自动未初始化变量,因为rvalue是未定义的行为.可以使用寄存器存储类说明符定义结构.
6.3.2.1
- 如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未使用其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何赋值) ),行为未定义.
请注意,它具体说明并且没有对其进行任何分配.
另外我们知道结构不能是陷阱值:
6.2.6.1.
- 结构或联合对象的值永远不是陷阱表示,即使结构或联合对象的成员的值可能是陷阱表示
因此,返回未初始化的结构显然是未定义的行为.
声明:定义了返回一个未初始化的结构,该结构的一个成员被赋予了有效值.
更容易理解的示例:
struct test
{
int a;
int b;
};
struct test Get( void )
{
struct test g;
g.a = 123;
return g;
}
{
struct test t = Get();
}
Run Code Online (Sandbox Code Playgroud)
我碰巧专注于回归,但我相信这也适用于简单的任务,没有任何区别.
我的陈述是否正确?
对于打包f0并f1放入同一字节的实现,下面的程序是定义的吗?
struct S0 {
unsigned f0:4;
signed f1:4;
} l_62;
int main (void) {
(l_62.f0 = 0) + (l_62.f1 = 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我对C99和C11的答案感兴趣,如果有理由认为它在那里是不同的.
在C99中,我发现的只有6.5:2:
在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的评估来修改一次.[...]
我不清楚这一段对上述计划有何影响.
基于大量随机测试,大多数编译器似乎生成代码,其中两个分配不会干扰.
为什么在C11或C++ 11中没有UTF-8字符文字,即使有UTF-8字符串文字?我理解,一般来说,字符文字表示单个ASCII字符,它与单个八位字节UTF-8代码点相同,但C和C++都没有说编码必须是ASCII.
基本上,如果我读取标准权限,则无法保证'0'将表示整数0x30,但u8"0"必须表示字符序列0x30 0x00.
编辑:
我知道不是每个UTF-8代码点都适合char.这样的文字只对单八位字节代码点(aka,ASCII)有用,所以我猜这称为"ASCII字符文字"会更合适,所以问题仍然存在.我只是选择用UTF-8构建问题,因为有UTF-8字符串文字.我可以想象可以保证ASCII值的唯一方法就是为每个字符写一个常量,考虑到只有128个,这不会那么糟糕,但仍然......
我理解单参数函数的C11泛型,如下所示:(从这里)
#define acos(X) _Generic((X), \
long double complex: cacosl, \
double complex: cacos, \
float complex: cacosf, \
long double: acosl, \
float: acosf, \
default: acos \
)(X)
Run Code Online (Sandbox Code Playgroud)
但是,对于具有两个参数的函数来说似乎很痛苦,你需要嵌套调用_Generic,这真的很难看; 摘自同一篇博客:
#define pow(x, y) _Generic((x), \
long double complex: cpowl, \
double complex: _Generic((y), \
long double complex: cpowl, \
default: cpow), \
float complex: _Generic((y), \
long double complex: cpowl, \
double complex: cpow, \
default: cpowf), \
long double: _Generic((y), \
long double complex: …Run Code Online (Sandbox Code Playgroud) 给定(简化)代码片段:
void foo(int a, int b); // declaration with prototype
int main(void)
{
foo(1, 5); // type-checked call (i.e. because of previous prototype)
return 0;
}
void foo() // old-style definition (with empty argument list)
{
}
Run Code Online (Sandbox Code Playgroud)
和命令行选项(但是,因为我检查它们并不重要):
-x c -std=c11 -pedantic -Wall
Run Code Online (Sandbox Code Playgroud)
gcc 7.2无法编译它,并显示以下错误消息:
错误:参数数量与原型不匹配
虽然clang 4.0翻译它没有任何投诉.
根据C标准,哪种实施方法是正确的?旧式定义"取消"以前的原型是否有效?
关于匿名结构和联合,遵守C标准:
6.7.2.1 p13. 类型说明符是没有标记的结构说明符的未命名成员称为匿名结构; 一个未命名的成员,其类型说明符是一个没有标记的联合说明符,称为匿名联合.匿名结构或联合的成员被视为包含结构或联合的成员.如果包含的结构或联合也是匿名的,则递归应用.
注意强调:而不是匿名struct/union的成员在包含struct/union 的范围内,它们是它的完全成员.但是有责任:
6.7.2.1 p16.联合的大小足以包含其最大的成员.最多一个成员的值可以随时存储在union对象中.指向适当转换的union对象的指针指向其每个成员(或者如果成员是位字段,则指向它所在的单位),反之亦然.
总而言之,这些似乎意味着(命名)联合中的匿名结构的成员表现得像联合的共同位置,相互排斥的成员.所以以下应该有效:
union Foo
{
struct
{
char a;
char b;
};
};
int main(void) {
union Foo f;
assert(&f == &(f.a) && &f == &(f.b));
}
Run Code Online (Sandbox Code Playgroud)
当然,它没有,我们也不希望它......如果他们像上面那样工作,那么没有理由建立匿名结构/联盟.尽管如此,该标准在这一点上似乎毫无疑问.有什么我想念的吗?