- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
上下文:
作为一名老 C 程序员(甚至是 K&R C...),我一直认为数组只不过是连续分配的非空对象集特定的成员对象类型,称为元素类型(来自 C11 标准的 n1570 草案,6.2.5 类型)。因此,我并不太担心指针算法。
我现在知道数组是一种对象类型,它只能通过定义 (6.1)、通过新表达式 (8.3.4) 创建,当隐式更改数组的事件成员时 union (12.3),或创建临时对象时 (7.4, 15.2)(来自 C++17 的 n4659 草案)。
问题:
我必须使用一个 C 库,其中一些函数返回指向 C 结构数组的指针。到目前为止一切顺利,C 结构是 POD 类型,正确的填充和对齐是通过使用编译器的标准标志实现的。但是由于数组的大小只有在运行时才知道,即使有正确的 extern "C"
声明,我的函数被声明为返回一个指向数组第一个元素的指针 - 实际大小是由 API 的不同函数返回。
简化示例:
#include <iostream>
extern "C" {
struct Elt {
int ival;
//...
};
void *libinit(); // initialize the library and get a handle
size_t getNElts(void *id); // get the number of elements
struct Elt* getElts(void *id); // get an access the the array of elements
void libend(void *id); // releases library internal data
}
int main() {
void *libid = libinit();
Elt* elts = getElts(libid);
size_t nelts = getNElts(libid);
for(int i=0; i<nelts; i++) {
std::cout << elts[i].ival << " "; // is elts[i] legal?
}
std::cout << std::endl;
libend(libid);
return 0;
}
问题:
我知道内存块可能是通过 malloc
分配的,这允许在其上使用指针,我假设 getElts(libid)[0]
不涉及未定义的行为。但是,在从未将 C 数组声明为 C++ 数组时,对 C 数组使用指针算术是否合法:API 仅保证我有一组连续分配的 Elt 类型对象 并且getElts
返回指向该集合第一个元素的指针。
因为 [expr.add] 明确限制数组内的指针算法:
4 When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements, the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[i + j] if 0 <= i + j <=n; otherwise, the behavior is undefined...
这曾经是一种常见的做法...
为了更清楚地说明我的问题,我知道如果用 C++ 完成,this 将是 UB
libstub.c++
/* C++ simulation of a C implementation */
extern "C" {
struct Elt {
int ival;
//...
};
void *libinit(); // initialize the library and get a handle
size_t getNElts(void *id); // get the number of elements
struct Elt* getElts(void *id); // get an access the the array of elements
void libend(void *id); // releases library internal data
}
size_t getCurrentSize() {
return 1024; // let us assume that the returned value is not a constexpr
}
void *libinit() {
size_t N = getCurrentSize();
unsigned char * storage = new unsigned char[(N + 1) * sizeof(Elt)];
// storage can provide storage for a size_t correct alignment
size_t *n = new(storage) size_t;
*n = N;
for (size_t i=1; i<=N; i++) {
// storage can provide storage for a size_t, correct alignment
Elt *elt = new(storage + (i+1) * sizeof(Elt)) Elt();
elt->ival = i; // put values into elt...
}
return static_cast<void *>(storage);
}
void libend(void * id) {
unsigned char *storage = static_cast<unsigned char *>(id); // ok, back cast is valid
delete[] storage; // ok, was allocated by new[]
}
size_t getNElts(void *id) {
size_t *n = reinterpret_cast<size_t *>(id); // ok a size_t was created there
return *n;
}
Elt *getElts(void *id) {
unsigned char *storage = static_cast<unsigned char *>(id); // ok, back cast
Elt* elt = reinterpret_cast<Elt *>(storage + sizeof(Elt)); // ok an Elt was created there
return elt;
}
这是有效的 C++ 代码,它满足 C API 要求。问题是 getElts
返回一个指向不属于任何数组成员的单个元素对象的指针。于是根据getElts
返回值的[expr.add]指针算法调用UB
最佳答案
就 C++ 而言,C 代码中发生的事情超出了 C++ 的范围。
所以“这个指针是否指向数组”是 C++ 标准无法回答的问题,因为指针来自 C 函数。相反,这是留给您的特定编译器的问题。
在实践中,这是可行的。理论上,当您以任何方式与 C 交互时,C++ 无法保证您的程序结构良好。
这是个好消息,因为 C++ 标准在创建类型 T 的动态数组方面被打破了。糟糕的是,没有编译器魔术就没有符合标准的方法来实现 std::vector
,或者由编译器定义因尝试执行此操作而导致的未定义行为。
但是,C++ 编译器可以自由地完全忽略这个问题。当对象被连续分配以表现得像数组时,它们可以自由定义元素间指针算法。我不知道有哪个编译器正式声明或保证这一点。
同样,他们可以自由地提供任何关于他们如何处理 C 代码中的指针的保证。在实践中,当您与 C 代码交互时,它们确实提供了相当合理的行为。
我不知道任何编译器有任何正式的保证。
关于c++ - 当涉及数组时,我们能否从 C++ 安全地调用 C API 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48111688/
我正在学习 Spring 安全性,但我对它的灵活性感到困惑.. 我知道我可以通过在标签中定义规则来保护网址 然后我看到有一个@secure 注释可以保护方法。 然后还有其他注释来保护域(或 POJO)
假设有一个 key 加密 key 位于内存中并且未写入文件或数据库... byte[] kek = new byte[32]; secureRandom.nextBytes(kek); byte[]
我有 Spring Security 3.2.0 RC1 的问题 我正在使用标签来连接我 这表示“方法‘setF
我正在创建一个使用 Node Js 服务器 API 的 Flutter 应用程序。对于授权,我决定将 JWT 与私钥/公钥一起使用。服务器和移动客户端之间的通信使用 HTTPS。 Flutter 应用
在过去的几年里,我一直在使用范围从 Raphael.js 的 javascript 库。至 D3 ,我已经为自己的教育操纵了来自网络各地的动画。我已经从各种 git 存储库下载了 js 脚本,例如 s
在 python 中实现身份验证的好方法是什么?已经存在的东西也很好。我需要它通过不受信任的网络连接进行身份验证。它不需要太高级,只要足以安全地获取通用密码即可。我查看了 ssl 模块。但那个模块让我
我正在尝试学习“如何在 Hadoop 中实现 Kerberos?”我已经看过这个文档 https://issues.apache.org/jira/browse/HADOOP-4487我还了解了基本的
我有一个带有 apache2、php、mysql 的生产服务器。我现在只有一个站点 (mysite.com) 作为虚拟主机。我想把 phpmyadmin、webalizer 和 webmin 放在那里
前些天在网上看到防火墙软件OPNsense,对其有了兴趣,以前写过一个其前面的一个软件M0n0wall( 关于m0n0wa
我在 Spring Boot 和 oauth2(由 Google 提供)上编写了 rest 后端,在 "/login" 上自动重定向。除了 web 的 oauth 之外,我还想在移动后端进行 Fire
我想调用类 Foo,它的构造函数中有抽象类 Base。我希望能够从派生自 Base 的 Derived 调用 Foo 并使用 Derived覆盖方法而不是 Base 的方法。 我只能按照指示使用原始指
如何提高 session 的安全性? $this->session->userdata('userid') 我一直在为我的 ajax 调用扔掉这个小坏蛋。有些情况我没有。然后我想,使用 DOM 中的
我目前正在为某些人提供程序集编译服务。他们可以在在线编辑器中输入汇编代码并进行编译。然后编译它时,代码通过ajax请求发送到我的服务器,编译并返回程序的输出。 但是,我想知道我可以做些什么来防止对服务
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
目前,我通过将 session 中的 key 与 MySQl 数据库中的相同 key 相匹配来验证用户 session 。我使用随机数重新生成 session ,该随机数在每个页面加载时都受 MD5
Microsoft 模式与实践团队提供了一个很棒的 pdf,称为:“构建安全的 asp.net 应用程序”。 microsoft pdf 由于它是为 .Net 1.0 编写的,所以现在有点旧了。有谁知
在 Lua 中,通常会使用 math.random 生成随机值和/或字符串。 & math.randomseed , 其中 os.time用于 math.randomseed . 然而,这种方法有一个
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我们有一个严重依赖 Ajax 的应用程序。确保对服务器端脚本的请求不是通过独立程序而是通过坐在浏览器上的实际用户的好方法是什么 最佳答案 真的没有。 通过浏览器发送的任何请求都可以由独立程序伪造。 归
我正在寻找使用 WebSockets 与我们的服务器通信来实现 web (angular) 和 iPhone 应用程序。在过去使用 HTTP 请求时,我们使用请求数据、url、时间戳等的哈希值来验证和
我是一名优秀的程序员,十分优秀!