如果您知道在到达有效区域的末尾之前找到该字符,那么调用长度过长的memchr是否合法?

Bee*_*ope 9 c language-lawyer c++11 c11

在C11和C++ 11 1中是否有以下定义的行为?

bool has4() {  
    char buf[10] = {0, 1, 2, 4};
    return memchr(buf, 4, 20);
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们通过了太长的时间memchr.数组有10个元素,但是我们传递了20.但是,我们要搜索的元素总是在结束之前找到.我很清楚这是否合法.

如果允许这样做,则会限制实现的灵活性,因为实现不能依赖于大小是可访问存储器区域大小的有效指示,因此必须小心读取超出找到的元素.一个例子是一个想要从传入指针开始执行16字节SIMD加载然后并行检查所有16个字节的实现.如果用户传递的长度为16,则只有在需要访问整个长度时才会安全.

否则(如果上面的代码是合法的),实现必须避免对目标元素之外的元素进行潜在的错误处理,例如通过对齐加载(可能很昂贵)或检查指针是否接近保护边界末尾.


1这里是一个罕见的问题,我猜C和C++的标记是有效的:据我所知,C++标准只是在行为方面通过引用直接推迟到C标准,但如果不是这样的话我想知道.

And*_*dyG 11

在C11和C++ 17中(强调我的)

void *memchr(const void *s, int c, size_t n);

memchr函数定位在指向的对象的初始字符(每个解释为)中的第一次出现c(转换为a unsigned char).实现的行为就像它按顺序读取字符一样,并在找到匹配字符后立即停止.nunsigned chars

只要memchr在你走出界限之前找到它正在寻找的东西,你就可以了.


C++ 11和C++ 14都使用C99,它没有这样的措辞.(他们参考ISO/IEC 9899:1999)

C99措辞:

void *memchr(const void *s, int c, size_t n);

memchr函数定位的第一次出现c(转化成unsigned char在初始)n字符(每个解释为unsigned char)的对象指向s.

如果不定义如果传递过大的尺寸发生了什么,该行为是未定义的C99

  • 因此,设置尝试达到对齐状态的“引入”代码可能会因短字符串/区域而影响性能,而这通常正是重要的。一个合理的策略是在几次迭代中做一些未对齐(廉价)的事情,直到达到某个交叉点,此时您假设字符串足够长并且翻转到对齐。有时,在现代硬件上根本不翻转对齐可能会更好。 (2认同)