小编Kyl*_*yle的帖子

澄清C11标准中的工会示例

以下示例在C11标准6.5.2.3中给出

以下不是有效的片段(因为联合类型在函数f中不可见):

struct t1 { int m; };
struct t2 { int m; };
int f(struct t1 *p1, struct t2 *p2)
{
   if (p1->m < 0)
   p2->m = -p2->m;
   return p1->m;
}
int g()
{
   union {
      struct t1 s1;
      struct t2 s2;
   } u;
   /* ... */
   return f(&u.s1, &u.s2);
}
Run Code Online (Sandbox Code Playgroud)

为什么联合类型对函数f可见是否重要?

在阅读相关部分几次时,我在包含部分中看不到任何禁止此内容的内容.

c unions c11

10
推荐指数
1
解决办法
192
查看次数

这种clang标准是否符合标准?

这将是一个长期的语言律师问题,所以我想快速说明为什么我发现它是相关的.我正在开展一个严格的标准合规性至关重要的项目(编写一种编译成C的语言).我要提供的示例似乎是clang部分的标准违规,因此,如果是这种情况,我想确认一下.

gcc说,带有指向限定限定指针的指针的条件不能与带有void指针的条件语句共存.另一方面,clang编译好的东西.这是一个示例程序:

#include <stdlib.h>

int main(void){
   int* restrict* A = malloc(8);
   A ? A : malloc(8);
   return 0;
   }
Run Code Online (Sandbox Code Playgroud)

对于GCC,选项-std=c11-pedantic可包括或不以任何组合,同样地对于铛和选项-std=c11-Weverything.在任何情况下,clang编译没有错误,gcc给出以下内容:

tem-2.c: In function ‘main’:
tem-2.c:7:2: error: invalid use of ‘restrict’
  A ? A : malloc(8);
  ^
Run Code Online (Sandbox Code Playgroud)

关于条件陈述,c11标准说明如下,强调增加:

6.5.15条件运算符

...

  1. 下列之一应适用于第二和第三操作数:

- 两个操作数都有算术类型;

- 两个操作数具有相同的结构或联合类型;

- 两个操作数都有空洞类型;

- 两个操作数都是兼容类型的限定或非限定版本的指针;

- 一个操作数是指针,另一个是空指针常量; 要么

- 一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的void的指针.

...

  1. 如果第二个和第三个操作数都是指针,或者一个是空指针常量而另一个是指针,则结果类型是指向使用两个操作数引用的类型的所有类型限定符限定的类型的指针.此外,如果两个操作数都是兼容类型的指针或兼容类型的不同限定版本,则结果类型是指向复合类型的适当限定版本的指针; 如果一个操作数是空指针常量,则结果具有另一个操作数的类型; 否则,一个操作数是指向void的指针或void的限定版本,在这种情况下,结果类型是指向适当限定版本的void的指针.

...

我看到它的方式,上面的第一个粗体部分表示两种类型可以一起使用,第二个粗体部分将结果定义为指向限制限定版本的void的指针.但是,如下所示,此类型不能存在,因此表达式被gcc正确识别为错误:

6.7.3类型限定词,第2段

引用类型为对象类型的指针类型以外的类型不应受限制.

现在,问题是这个示例程序违反了"不应该"的条件,因此需要通过以下方式产生错误:

5.1.1.3诊断,第1段

如果预处理转换单元或转换单元包含违反任何语法规则或约束的情况,则符合要求的实现应生成至少一条诊断消息(以实现定义的方式标识),即使该行为也明确指定为未定义或实现 - 定义.在其他情况下不需要产生诊断消息.

通过静默处理错误类型,似乎clang不符合标准.这让我想知道铿锵有什么其他的默默无闻.

我在x86-64 Ubuntu机器上使用gcc版本5.4.0和clang版本3.8.0.

c compiler-errors clang restrict c11

9
推荐指数
1
解决办法
199
查看次数

POSIX C中fork()的重量更轻?

在我一直在阅读的手册页中,似乎popen,system等倾向于调用fork().反过来,fork()复制进程的整个内存状态.这看起来非常重,特别是在很多情况下,来自fork()的调用的子节点几乎没有为父节点分配任何内存.

所以,我的问题是,我可以获得fork()之类的行为,而不会复制父进程的整个内存状态吗?或者有什么我缺少的东西,这样fork()没有它看起来那么重(比如,可能调用往往会被优化以避免不必要的内存重复)?

c posix fork

6
推荐指数
1
解决办法
1607
查看次数

是通过令牌连接未指定的行为重复宏调用吗?

C11标准承认关于宏扩展中可能出现的至少一种情况的模糊性,当像宏这样的函数扩展到其未被识别的名称时,并且由下一个预处理令牌调用.标准中给出的例子是这样的.

#define f(a) a*g
#define g(a) f(a)

// may produce either 2*f(9) or 2*9*g
f(2)(9)
Run Code Online (Sandbox Code Playgroud)

该示例没有说明当扩展宏M时会发生什么,并且结果的全部或部分通过令牌连接贡献给被调用的第二预处理令牌M.

问题:这样的调用被阻止了吗?

这是一个这样的调用的例子.这个问题往往只在使用一组相当复杂的宏时出现,所以这个例子是为了简单起见而设计的.

// arity gives the arity of its args as a decimal integer (good up to 4 args)
#define arity(...) arity_help(__VA_ARGS__,4,3,2,1,)
#define arity_help(_1,_2,_3,_4,_5,...) _5

// define 'test' to mimic 'arity' by calling it twice
#define test(...) test_help_A( arity(__VA_ARGS__) )
#define test_help_A(k) test_help_B(k)
#define test_help_B(k) test_help_##k
#define test_help_1 arity(1)
#define test_help_2 arity(1,2)
#define test_help_3 arity(1,2,3)
#define test_help_4 arity(1,2,3,4)

// does this expand to '1' …
Run Code Online (Sandbox Code Playgroud)

c macros c-preprocessor c11

5
推荐指数
1
解决办法
84
查看次数

在指定指针时使用指向内容

我一直认为,在赋值中读取正确表达式后缺少序列点会产生如下示例,产生未定义的行为:

void f(void)
{
   int *p;
   /*...*/
   p = (int [2]){*p};
   /*...*/
}
// p is assigned the address of the first element of an array of two ints, the
// first having the value previously pointed to by p and the second, zero. The
// expressions in this compound literal need not be constant. The unnamed object
// has automatic storage duration.
Run Code Online (Sandbox Code Playgroud)

但是,这是C11标准委员会草案中"6.5.2.5复合文字"下的例2,该版本标识为n1570,我理解为最终草案(我无法访问最终版本).

所以,我的问题是:标准中是否有某些内容可以提供此定义和指定的行为?

编辑

我想详细阐述我所看到的问题,以回应一些已经提出的讨论.

根据dbush给出的答案中引用的6.5p2标准,我们有两个条件明确指出赋值具有未定义的行为:

1)相对于对同一标量对象的不同副作用,对标量对象的副作用是无效的.

2)相对于使用相同标量对象的值的值计算,对标量对象的副作用是未序的.

项目1的示例是"i = ++ i + 1".在这种情况下,由于++ i而将值i + 1写入i的副作用相对于将RHS分配给LHS的副作用而言是无效的.每一侧的值计算和RHS与LHS的分配之间存在一个序列点,如下面Jens Gustedt的答案中给出的6.5.16.1中所述.但是,由于++ …

c variable-assignment compound-literals c11

5
推荐指数
2
解决办法
99
查看次数

现代终端通常能正确呈现所有utf-8字符吗?

我在C中编写一个将在终端中运行的应用程序,使用一些较少使用的unicode字符会很方便但不是必需的.从我的实验中,我没有遇到任何麻烦.但是,如果将来可能出现问题,我不会使用任何非ascii字符.

那么,简而言之,我可以依靠现代*nix世界中的任何终端或终端模拟器(主要是linux,freebsd和osx)来正确渲染任意utf-8字符吗?

如果我不能做出这样的假设,那么为特定目的定义了特定的unicode字符子集,那么至少可以在任何可能的现代*nix终端或终端仿真器中可靠地呈现某些这样的子集吗?

注意:当我说任意时,我的意思是任意的:任何unicode字符.但为了完整我的问题,我会注意到我主要对箭头和数学字符感兴趣,这个链接有两个列表:https://en.wikipedia.org/wiki/Unicode_symbols.

c linux unicode portability

4
推荐指数
1
解决办法
193
查看次数

Linux中的双向管道

因此,如果我在gcc stdio.h中使用popen(),我可以将父级的stdout传递给其子级的stdin,或者我可以将子级的stdout传递给父级的stdin.我想同时做两件事.有没有办法使用popen来做到这一点,或者我是否需要使用较低级别的工具(如共享内存)来完成这项工作?

注意:在FreeBSD中看起来popen可以用"r +"进行读写.我不明白孩子的stdout是如何通过管道输送到父母和父母的标准输出.不管怎么说,这可能对我有用,但在Linux中似乎并非如此.如果我在这一点上弄错了,那就会回答我的问题.以下是我收到此说明的链接:https://www.freebsd.org/cgi/man.cgi?query = popen&sektion = 3

注2:我更喜欢按照优先顺序在几乎所有Linux发行版,FreeBSD和OSX上移植的解决方案.话虽这么说,我很乐意至少让它在Ubuntu 14.04中运行.

c linux popen

2
推荐指数
1
解决办法
1122
查看次数

是否有定义的方法在C11中进行指针减法?

有没有办法在C11中从另一个指针中减去一个指针,并且总是定义结果?

如果结果不能表示为类型ptrdiff_t,则标准表示行为未定义.

我对依赖于静态断言的解决方案持开放态度,这些断言有望在现代通用32或64位环境中传递合理的实现.我想避免依赖任何类型的运行时检查的解决方案.

如果指向的类型的大小大于1,我可以静态断言size_t和ptrdiff_t具有相同数量的非填充位.这种局部解决方案依赖于我不确定的两件事,所以对此的任何反馈都会提供部分答案:

  1. 在现代通用32或64位环境中的合理实现中,可以预期ptrdiff_t具有比size_t少至少一个值位.

  2. 我对标准的理解是正确的,因为定义了两个指向大小大于1的对象的指针之间的差异,即使指针被强制转换为字符指针时,也会定义相同的差异.这种理解似乎与委员会草案中的脚注106不一致,但我的理解是脚注不是规范性的.

2
推荐指数
1
解决办法
831
查看次数

后缀和前缀是否在C11中递增和递减表达式左值?

后缀和前缀是否在C11中递增和递减表达式左值?通常,标准在底部有注释,指定给定表达式是否为左值.在这种情况下,我在标准中找不到任何东西.

我知道大多数时候会出现序列点问题,但是有一些边缘情况似乎对此有用.例如,在6.5.2.4中:

具有原子类型的对象上的Postfix ++是具有memory_order_seq_cst内存顺序语义的读取 - 修改 - 写入操作.

因此,对于原子类型,像++ x = x + y这样的东西将是一种简单的做事方式.并不是说能够做这样的事情很重要,我只是不喜欢不了解事情.

c lvalue c11

1
推荐指数
1
解决办法
184
查看次数