Tag: 语言 律师

比特域的类型是什么?

我在C标准中找不到指定的任何地方。 例如,在 struct { signed int x:1; } foo; 是foo.x是int类型的左值还是其他什么? 因为你不能在其中存储int类型的任何值,只有0或-1,但是我找不到任何可以为它分配不同类型的语言,因此它似乎不自然地成为int类型的左值。 当然,在大多数表达式中使用它,无论如何它都会被提升为int ,但是实际的类型在C11中与_Generic有所不同,我在标准中找不到任何关于bitfields如何与_Generic交互的语言。

“解除引用”这个词来自哪里?

这个问题将从N1570草案中提取信息 ,所以基本上是C11。 通俗地说,取消引用指针意味着将一元*运算符应用于指针。 草案文件中只有一个“解除引用”一词的地方(没有“解除引用”的例子),它在脚注中: 102)[…] 用于通过一元*运算符解除引用指针的无效值包括空指针,为指向的对象类型不恰当地对齐的地址,以及对象在其生命周期结束后的地址 据我所知,一元*运算符实际上被称为“间接运算符”,如§6.5.3.2所示: 6.5.3.2地址和间接运营商 4一元*运算符表示间接。 […] 同时,它在附件§J.2中被明确地称为间接运算符: – 对象的值由array-subscript [] ,member-access访问. 或−> ,地址&或间接*运算符或在创建地址常量(6.6)时强制转换的指针。 那么在C中谈论“解除引用指针”是否正确或者这是否过于迂腐? 术语来自哪里? (由于§6.5.2.1,我可以给[]传递称为“引用”

是否 和(* a)等效为函数参数?

function原型 void foo(int n, int a[][]); 给出了关于不完整类型的错误 void foo(int n, int (*a)[]); 编译。 根据衰减规则int a[][]在这种情况下等效于int (*a)[] ,因此int (*a)[]也应该给出关于不完整类型的错误,但GCC似乎接受它。 有什么我想念的吗? 这可能是一个GCC错误,但我没有发现任何与之相关的内容。

获取未初始化指针的地址是未定义的行为吗?

N1570声明这是未定义的行为: §J.2/ 1具有自动存储持续时间的对象的值在不确定时使用(6.2.4,6.7.9,6.8)。 在这种情况下,我们的指针具有不确定的值: §6.7.9/ 10如果没有显式初始化具有自动存储持续时间的对象,则其值是不确定的。 如果未显式初始化具有静态或线程存储持续时间的对象,则: – 如果它有指针类型,则将其初始化为空指针; 然后,我假设以下测试程序显示未定义的行为: #include int main(void) { char * ptr; printf(“%p”, (void*)&ptr); } 我的动机是strtolfunction。 首先,让我引用与endptr参数相关的endptr : §7.22.1.4/ 5如果主题序列具有预期forms且base的值为零,则根据6.4.4.1的规则将以第一个数字开头的字符序列解释为整数常量。 […]指向最终字符串的指针存储在endptr指向的对象中,前提是endptr不是空指针。 §7.22.1.4/ 7如果主题序列为空或没有预期的forms,则不进行转换; 如果endptr不是空指针,则nptr的值存储在endptr指向的对象中。 这意味着endptr需要指向一个对象,并且该endptr在某个时候被解除引用。 例如, 此实现是这样做的 : if (endptr != 0) *endptr = (char *)(any ? s – 1 : nptr); 然而, 这个高度赞成的答案以及这个手册页都显示endptr被传递给strtol未初始化。 是否有一个exception导致这种未定义的行为?

数组外的指针比较的基本原理是UB

因此,标准(参考N1570 )说明了以下关于比较指针的内容: C99 6.5.8 / 5关系运算符 比较两个指针时,结果取决于指向的对象的地址空间中的相对位置。 … [在聚合中剪切明显的比较定义] … 在所有其他情况下,行为是未定义的。 这个UB实例的基本原理是什么,而不是指定(例如)转换为intptr_t并进行比较? 是否存在一些机器架构,其中指针的合理总排序难以构建? 是否存在一些优化或分析,不受限制的指针比较会阻碍? 这个问题的删除答案提到这块UB允许跳过段寄存器的比较并且仅比较偏移。 保存特别有价值吗? (同样删除的答案,以及此处的答案,请注意,在C ++中, std::less等是实现指针总顺序所必需的,无论普通比较运算符是否执行。)

C中“array”的定义是什么?

该标准精心定义了数组类型 ,但我没有看到任何数组定义。 我们可能会说“数组类型的对象”,但是这不能正确,因为无类型对象(例如malloc分配的空间)被描述为数组。 动机: fprintf (C11 7.21.6.1/8)中%s的规格说: 参数应该是指向字符类型数组的初始元素的指针 但是取代码char s[] = “hello”; printf(“%s”, s+1); char s[] = “hello”; printf(“%s”, s+1); 然后我们传递了一个指向第二个元素的指针。 该定义似乎假设该数组表示任何一组连续的对象 。 编辑:看到我已经选择了一些“不清楚你要问的”投票,我的问题是:ISO / IEC 9899:2011使用的术语数组的定义是什么?

根据标准,C中的指针标记是否未定义?

一些动态类型语言使用指针标记作为识别或缩小所表示值的运行时类型的快速方法。 执行此操作的经典方法是将指针转换为适当大小的整数,并在最低有效位上添加标记值,对于对齐对象,这些位被假定为零。 当需要访问对象时,标记位被屏蔽掉,整数转换为指针,指针被正常解除引用。 这本身就是有序的,除了它都取决于一个巨大的假设:对齐的指针将转换为保证在正确位置具有零位的整数。 是否可以根据标准的字母来保证这一点? 虽然标准的6.3.2.3节(参考C11草案)说从指针到整数的转换结果是实现定义的,但我想知道的是6.5.2.1和6.5.6中的指针算术规则是否有效约束指针 – >整数转换的结果遵循许多程序已经假设的相同的可预测算术规则。 (6.3.2.3注释67似乎表明这是标准的预期精神 ,而不是那意味着很多。) 我特别想到的情况是,人们可能会分配一个大型数组作为动态语言的堆,因此我们所讨论的指针就是这个数组的元素。 我假设C分配数组本身的开始可以通过某些辅助手段放置在对齐位置(尽管如此也是这样讨论)。 假设我们有一个八字节“cons cell”数组; 我们可以保证指向任何给定单元格的指针将转换为标记最低三位的整数吗? 例如: typedef Cell …; // such that sizeof(Cell) == 8 Cell heap[1024]; // such that ((uintptr_t)&heap[0]) & 7 == 0 ((char *)&heap[11]) – ((char *)&heap[10]); // == 8 (Cell *)(((char *)&heap[10]) + 8); // == &heap[11] &(&heap[10])[0]; // == &heap[10] […]

限制指针算术或比较的基本原理是什么?

在C / C ++中,仅当结果指针位于原始指向的完整对象内时,才定义指针的加法或减法 。 此外,只有当两个指向对象是唯一完整对象的子对象时,才能执行两个指针的比较 。 这种限制的原因是什么? 我认为分段内存模型(参见此处 §1.2.1)可能是其中一个原因,但由于编译器实际上可以定义所有指针的总顺序,如此答案所示 ,我对此表示怀疑。

外部声明,T * v / s T

我在遗留项目中看到了以下代码片段。 /* token.c */ struct token id_tokens[MAX_TOKENS]; /* analyse.c (v1) */ extern struct token *id_tokens; /* Raised my eyebrow, id_token declares a pointer */ 我坚持要更改analyse.c以包含如下声明: /* analyse.c (v2) */ extern struct token id_tokens[]; /* I am happy with this. id_tokens declares array of unspecified size. */ 我想要v2因为pointer to T array of T 。 我朋友的反驳说,两者的行为都是一样的,所以我使用v1和v2并不重要。 问题1:不完整类型的数组是否耗尽指针? […]

为什么SCHAR_MIN在C99中定义为-127?

C99的5.2.4.2.1将SCHAR_MIN定义为-127,将SCHAR_MAX定义为127. 8位有符号整数的范围不应该是-128到+127吗? 我的编译器的limits.h将SCHAR_MIN定义为(-1 << ((CHAR_BIT)-1)) ,如果CHAR_BIT为8,则为-128。 是否有任何理由为什么SCHAR_MIN被定义为-127而不是-128?