- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在另一个问题的热门评论线程之后,我开始讨论 C99 标准中关于 C 数组定义的内容和未定义的内容。
基本上,当我定义像 int a[5][5]
这样的二维数组时,标准 C99 是否保证它将是一个连续的整数 block ,我可以将它转换为 (int *)a
并确保我将拥有一个包含 25 个整数的有效一维数组。
根据我对标准的理解,上述属性隐含在 sizeof 定义和指针运算中,但其他人似乎不同意并表示转换为 (int*) 上述结构会产生未定义的行为(即使他们同意 所有现有的实现实际上分配了连续的值)。
更具体地说,如果我们认为一个实现会检测数组以检查所有维度的数组边界并在访问一维数组时返回某种错误,或者不能正确访问第一行以上的元素。这样的实现可以符合标准吗?在这种情况下,C99 标准的哪些部分是相关的。
最佳答案
我们应该首先检查 int a[5][5] 到底是什么。涉及的类型有:
不涉及整数数组[25]。
正确的是,sizeof 语义暗示数组作为一个整体是连续的。 ints的array[5]必须有5*sizeof(int),递归应用,a[5][5]必须有5*5*sizeof(int)。没有额外填充的空间。
此外,当以 sizeof 赋给 memset、memmove 或 memcpy 时,整个数组必须正常工作。还必须可以使用 (char *) 遍历整个数组。所以一个有效的迭代是:
int a[5][5], i, *pi;
char *pc;
pc = (char *)(&a[0][0]);
for (i = 0; i < 25; i++)
{
pi = (int *)pc;
DoSomething(pi);
pc += sizeof(int);
}
对 (int *) 做同样的事情将是未定义的行为,因为如前所述,没有涉及 int 的数组 [25]。在 Christoph 的回答中使用 union 也应该是有效的。但是还有一点使这进一步复杂化,相等运算符:
6.5.9.6两个指针比较相等当且仅当它们都是空指针,都是指向同一个对象(包括指向对象和其开头的子对象的指针)或函数的指针,都是指向同一数组最后一个元素的指针对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的开始的指针,该对象恰好紧跟在地址空间中的第一个数组对象之后。 91)
91) 两个对象在内存中可能相邻,因为它们是更大数组的相邻元素或结构的相邻成员,它们之间没有填充,或者因为实现选择这样放置它们,即使它们不相关。如果先前的无效指针操作(例如访问数组边界之外)产生未定义的行为,则后续比较也会产生未定义的行为。
这意味着:
int a[5][5], *i1, *i2;
i1 = &a[0][0] + 5;
i2 = &a[1][0];
i1 比较等于 i2。但是当用 (int *) 遍历数组时,它仍然是未定义的行为,因为它最初是从第一个子数组派生的。它不会神奇地转换为指向第二个子数组的指针。
即使这样做
char *c = (char *)(&a[0][0]) + 5*sizeof(int);
int *i3 = (int *)c;
没用。它比较等于 i1 和 i2,但它不是从任何子数组派生的;它最多是一个指向单个 int 或 int 数组 [1] 的指针。
我不认为这是标准中的错误。恰恰相反:允许这样做会引入一种特殊情况,这种情况要么违反数组的类型系统,要么违反指针算法的规则,或者两者兼而有之。它可能被认为是缺少定义,但不是错误。
因此,即使 a[5][5] 的内存布局与 a[25] 的布局相同,并且可以使用使用 (char *) 的相同循环来迭代两者,一个实现是如果一个用作另一个,则允许爆炸。我不知道为什么它应该或知道任何实现,也许标准中有一个直到现在才提到的事实使它成为明确定义的行为。在那之前,我会认为它是未定义的并保持安全。
关于c - C99 是否保证数组是连续的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2832970/
我有一个 if 语句,如下所示 if (not(fullpath.lower().endswith(".pdf")) or not (fullpath.lower().endswith(tup
然而,在 PHP 中,可以: only appears if $foo is true. only appears if $foo is false. 在 Javascript 中,能否在一个脚
XML有很多好处。它既是机器可读的,也是人类可读的,它具有标准化的格式,并且用途广泛。 它也有一些缺点。它是冗长的,不是传输大量数据的非常有效的方法。 XML最有用的方面之一是模式语言。使用模式,您可
由于长期使用 SQL2000,我并没有真正深入了解公用表表达式。 我给出的答案here (#4025380)和 here (#4018793)违背了潮流,因为他们没有使用 CTE。 我很欣赏它们对于递
我有一个应用程序: void deleteObj(id){ MyObj obj = getObjById(id); if (obj == null) { throw n
我的代码如下。可能我以类似的方式多次使用它,即简单地说,我正在以这种方式管理 session 和事务: List users= null; try{ sess
在开发J2EE Web应用程序时,我通常会按以下方式组织我的包结构 com.jameselsey.. 控制器-控制器/操作转到此处 服务-事务服务类,由控制器调用 域-应用程序使用的我的域类/对象 D
这更多是出于好奇而不是任何重要问题,但我只是想知道 memmove 中的以下片段文档: Copying takes place as if an intermediate buffer were us
路径压缩涉及将根指定为路径上每个节点的新父节点——这可能会降低根的等级,并可能降低路径上所有节点的等级。有办法解决这个问题吗?有必要处理这个吗?或者,也许可以将等级视为树高的上限而不是确切的高度? 谢
我有两个类,A 和 B。A 是 B 的父类,我有一个函数接收指向 A 类型类的指针,检查它是否也是 B 类型,如果是将调用另一个函数,该函数接受一个指向类型 B 的类的指针。当函数调用另一个函数时,我
有没有办法让 valgrind 使用多个处理器? 我正在使用 valgrind 的 callgrind 进行一些瓶颈分析,并注意到我的应用程序中的资源使用行为与在 valgrind/callgrind
假设我们要使用 ReaderT [(a,b)]超过 Maybe monad,然后我们想在列表中进行查找。 现在,一个简单且不常见的方法是: 第一种可能性 find a = ReaderT (looku
我的代码似乎有问题。我需要说的是: if ( $('html').attr('lang').val() == 'fr-FR' ) { // do this } else { // do
根据this文章(2018 年 4 月)AKS 在可用性集中运行时能够跨故障域智能放置 Pod,但尚不考虑更新域。很快就会使用更新域将 Pod 放入 AKS 中吗? 最佳答案 当您设置集群时,它已经自
course | section | type comart2 : bsit201 : lec comart2 :
我正在开发自己的 SDK,而这又依赖于某些第 3 方 SDK。例如 - OkHttp。 我应该将 OkHttp 添加到我的 build.gradle 中,还是让我的 SDK 用户包含它?在这种情况下,
随着 Rust 越来越充实,我对它的兴趣开始激起。我喜欢它支持代数数据类型,尤其是那些匹配的事实,但是对其他功能习语有什么想法吗? 例如标准库中是否有标准过滤器/映射/归约函数的集合,更重要的是,您能
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 9 年前。 Improve
我一直在研究 PHP 中的对象。我见过的所有示例甚至在它们自己的对象上都使用了对象构造函数。 PHP 会强制您这样做吗?如果是,为什么? 例如: firstname = $firstname;
...比关联数组? 关联数组会占用更多内存吗? $arr = array(1, 1, 1); $arr[10] = 1; $arr[] = 1; // <- index is 11; does the
我是一名优秀的程序员,十分优秀!