Tag: 语言 律师

返回语句后的序列点?

在我对这里的一个问题的回答中,我解释了当postfix ++在与return语句相同的行上的全局变量上使用时发生了什么。 C11的资料性附录C表明在return后立即有一个序列点,并参考规范性章节6.8.6.4,其中没有关于序列点的文本可以找到。 我可以在C标准中找到规范性文本,说明return语句后有一个序列点吗? (我只在7.1.4 / 3中找到了规范文本,用于库函数,作为一个特殊情况。)

用联合检测endianess是否安全?

换句话说,根据C 标准 ,这段代码是否安全? (假设uint8_t是一个字节) void detectEndianness(void){ union { uint16_t w; uint8_t b; } a; aw = 0x00FFU; if (ab == 0xFFU) { puts(“Little endian.”); } else if (ab == 0U) { puts(“Big endian.”); } else { puts(“Stack Overflow endian.”); } } 如果我把它改成这个怎么办? 注意第三个我知道的情况。 aw = 1U; if (ab == 1U) { puts(“Little endian.”); } else […]

是什么让glibc malloc可以比较来自不同“对象”的指针?

比较指针与关系运算符(例如< , <= , >=或> )仅在指针指向同一聚合对象(结构,数组或联合)时由C标准定义。 这在实践中意味着形状的比较 if (start_object <= my_pointer && my_pointer < end_object+1) { 可以变成 if (1) { 通过优化编译器。 尽管如此,在K&R的第8.7节“示例 – 存储分配器”中,作者进行了与上述类似的比较。 他们原谅这个说法 然而,仍有一个假设是,可以有意义地比较sbrk返回的不同块的指针。 标准不保证这一点,它只允许在数组中进行指针比较。 因此,这个版本的malloc只能在一般指针比较有意义的机器之间移植。 而且,看来glibc中使用的malloc的实现做了同样的事情! 更糟糕的是 – 我偶然发现这一点的原因是 – 对于学校作业,我应该实现一个基本的类似function,并且作业的指示要求我们使用K&R代码,但我们必须更换通过调用mmap调用sbrk ! 虽然比较来自不同sbrk调用的指针可能是未定义的,但它也只是略微可疑,因为你有某种心理直觉,返回的指针应该来自同一个内存区域。 根据我的理解,由不同的mmap调用返回的指针甚至不能保证彼此远程相似,并且在mmap调用之间合并/合并内存块应该是非常非法的(并且看起来glibc避免了这种情况,只采用合并由sbrk或mmap页面内部返回的内存,而不是它们之间的内存),但是赋值需要这样。 问题:有人可以发光 是否可以优化将来自不同调用的指针与sbrk进行比较 如果是这样, glibc做什么让他们逃脱它。

是否存在else if语句?

前一段时间没有站在这样的线路之后: if (arg) invk(test); else if (test) { alot(); stuff(); } 我决定在1920×1200次中为自己提供更好的可读性,而不是省略{} 。 所以我写了一个工具来重新格式化我现有的代码。 后来我注意到该工具中的一个错误 if (x) { … } else if(y) { … } else if(z) { … } 已经被改变了(没有通过不经意地改变行为)成: if (x) { … } else { if(y) { … } else { if(z) { … } } } 这让我意识到(无意识)这实际上是C语言和语义规则的其他内容。 那么甚至还有一个像else if()现有的声明,或者它只是滥用语义导致这个有用但是(为了这个目的让我们称它)混淆起源的措辞打破了任何格式化规则并且只是作为人类可读的?

是否错误地指定了严格别名规则?

如前所述,forms的联合 union some_union { type_a member_a; type_b member_b; … }; n个成员在重叠存储中包含n + 1个对象:一个对象用于union本身,一个对象用于每个union成员。 很明显,您可以按任何顺序自由地读取和写入任何工会成员,即使读取的工会成员不是最后写入的工会成员。 严格别名规则永远不会被违反,因为您访问存储的左值具有正确的有效类型。 脚注95 进一步支持了这一点,脚注95解释了类型双关语是否是联盟的预期用途。 严格别名规则启用的优化的典型示例是此函数: int strict_aliasing_example(int *i, float *f) { *i = 1; *f = 1.0; return (*i); } 编译器可以优化到类似的东西 int strict_aliasing_example(int *i, float *f) { *i = 1; *f = 1.0; return (1); } 因为它可以安全地假设写入*f不会影响*i的值。 但是,当我们将两个指针传递给同一个联盟的成员时会发生什么? 考虑这个例子,假设一个典型的平台,其中float是IEEE 754单精度浮点数, int是32位二进制补码整数: int […]

UB是否会抛弃const和读取值?

澄清:我的问题是: UB是否使用int类型的左值来访问有效类型为const int的对象? 这个问题有两个代码示例,它们使用类型为int的左值来访问有效类型为const int的对象,我的目的是尽可能少地分散对象。 如果除了这个特定问题之外还有任何其他UB来源,请发表评论,我将尝试更新代码示例。 以下是讨论的具体代码示例: #include #include int main() { const int c = 5; printf(“%d\n”, *(int *)&c); } 我认为它可能是UB的原因是严格的别名规则似乎说它是UB: C11 6.5 / 7 对象的存储值只能由具有以下类型之一的左值表达式访问: 与对象的有效类型兼容的类型, 与对象的有效类型兼容的类型的限定版本, … 这里对象的有效类型 (6.5 / 6)是const int 。 第一个要点: int和const int不兼容类型 (6.2.7 / 1,6.7.3 / 10)。 第二个要点: int似乎不是const int的限定版本,因为我们没有通过添加限定符来生成它。 但是6.2.5 / 26不清楚: 每个非限定类型都有几个类型的限定版本,对应于const,volatile和restrict限定符中的一个,两个或全部三个的组合。 类型的限定或非限定版本是属于相同类型类别且具有相同表示和对齐要求的不同类型。 派生类型不是由派生类型的限定符(如果有)限定的。 它没有定义“ const […]

调用函数指针时,星号是否可选?

我无法在任何地方找到答案。 我刚看完K&R,看到他们调用这样的函数指针: (*ptr)(arg1, arg2); 然而,我清楚地记得看到有人像这样使用它们: ptr(arg1, arg2); 但这可能是在C ++中。 规则怎么样? 它们在C和C ++上有区别吗?

是否假定C / C ++中的所有函数都返回?

我正在阅读关于未定义行为的本文 ,其中一个示例“优化”看起来非常可疑: if (arg2 == 0) ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg(“division by zero”))); /* No overflow is possible */ PG_RETURN_INT32((int32) arg1 / arg2); 图2 :意外的优化使PostgreSQL的src/backend/utils/adt/int8.c中的除零检查src/backend/utils/adt/int8.c 。 对ereport(ERROR, :::)的调用将引发exception。 本质上,编译器假定 ereport将返回,并删除arg2 == 0检查,因为除法的存在意味着非零分母,即arg2 != 0 。 这是一个有效的优化吗? 编译器是否可以自由地假设函数将始终返回? 编辑:整个事情取决于电子报,因此描述: 84 /*———- 85 * New-style error reporting API: to be used in this way: 86 * ereport(ERROR, 87 * […]

指针到数组重叠的数组末尾

这段代码是否正确? int arr[2]; int (*ptr)[2] = (int (*)[2]) &arr[1]; ptr[0][0] = 0; 显然,通过访问超出范围的arr ptr[0][1]将是无效的。 注意:毫无疑问, ptr[0][0]指定的内存位置与arr[1] ; 问题是我们是否被允许通过ptr访问该内存位置。 下面是一些表达式确定指定相同内存位置但不允许以这种方式访问​​内存位置的示例。 注2:还要考虑**ptr = 0; 。 正如Marc van Leeuwen所指出的, ptr[0]相当于*(ptr + 0) ,但是ptr + 0似乎与指针运算部分相悖。 但是通过使用*ptr代替,可以避免这种情况。

关于C中数组初始化的困惑

在C语言中,如果初始化一个这样的数组: int a[5] = {1,2}; 那么未明确初始化的数组的所有元素将用零隐式初始化。 但是,如果我初始化这样的数组: int a[5]={a[2]=1}; printf(“%d %d %d %d %d\n”, a[0], a[1],a[2], a[3], a[4]); 输出: 1 0 1 0 0 我不明白,为什么a[0]打印1而不是0 ? 是不确定的行为? 注意:这个问题在接受采访时被问到。