我试图理解 Visual Studio 2022 中这一特定建议背后的原因,因为它对我来说似乎没有意义。这是简单的代码:
static constexpr uint32_t MAX_ELEMENTS = 100000;
const std::vector<int> A{ some random ints };
std::vector<bool> found(MAX_ELEMENTS);
for (int value : A)
{
if (value > 0 && value <= MAX_ELEMENTS)
found[value - 1] = true; // Problem it complains about is the value - 1.
}
Run Code Online (Sandbox Code Playgroud)
它表明“子表达式在添加到更广泛的类型之前可能会溢出”。现在显然条件 if 阻止了这种情况的发生,但是这里的推理是什么?
现在,如果这是 Spectre 的事情,我可以理解编译器会添加内存栅栏来停止 if 之后语句的任何推测执行,但我不认为这就是答案。
我唯一的想法是它与向量上的下标运算符有关;它的索引是大于 int 的类型并且隐式转换为 size_t?
下面的问题似乎有点不直观:
found[value - 1]
Run Code Online (Sandbox Code Playgroud)
这样做完全没问题,
int a = value - 1;
found[a];
Run Code Online (Sandbox Code Playgroud)
当最终结果相同时。就理解而言,我在这里缺少什么?
对不起,这不是一个问题,而是帮助人们解决这些特殊问题.我正在处理的问题需要使用串行I/O,但主要是在Windows CE 6.0下运行.但是,最近我被问到应用程序是否也可以在Windows下运行,所以我开始着手解决这个问题.我确实花了很多时间环顾四周,看看是否有人得到了我正在寻找的答案,这些都是在很多错误信息和一些事情中基本上都是错误的事情.所以解决了这个问题,我想我会和每个人分享我的发现,所以任何遇到这些困难的人都会得到答案.
在Windows CE下,不支持OVERLAPPED I/O. 这意味着通过串口的双向通信可能非常麻烦.主要的问题是,当您等待来自串行端口的数据时,您无法发送数据,因为这样做会导致主线程阻塞,直到读取操作完成或超时(取决于您是否设置了超时)
像大多数人一样做串行I/O,我有一个读取器串行线程设置用于读取串行端口,它使用WaitCommEvent()和EV_RXCHAR掩码来等待串行数据.现在,这就是Windows和Windows CE出现问题的地方.
如果我有这样一个简单的读者线程,作为一个例子: -
UINT SimpleReaderThread(LPVOID thParam)
{
DWORD eMask;
WaitCommEvent(thParam, &eMask, NULL);
MessageBox(NULL, TEXT("Thread Exited"), TEXT("Hello"), MB_OK);
}
Run Code Online (Sandbox Code Playgroud)
显然,在上面的例子中,我没有从串口或任何读取数据和我假设thParam包含打开的句柄通讯端口等.现在的问题是在Windows下当你的线程执行,并打WaitCommEvent(),您的读者线程将进入休眠状态等待串口数据.好的,这很好,应该如此,但是...你如何结束这个线程并让MessageBox()出现?事实证明,它实际上并不那么容易,并且它在执行其串行I/O方面是Windows CE和Windows之间的根本区别.
在Windows CE,你可以做几件事情,使WaitCommEvent()告吹,如SetCommMask(COMMPORT_HANDLE,0),甚至CloseHandle的(COMMPORT_HANDLE).这将允许您正确终止线程,因此释放串口以便您再次开始发送数据.但是这些东西都不能在Windows下运行,并且两者都会导致你调用它们的线程在WaitCommEvent()完成时等待.那么,你如何结束Windows下的WaitCommEvent()?那么,通常你会使用重叠I/O和线程阻塞不会是一个问题,但由于该解决方案必须与Windows CE兼容以及,重叠I/O是不是一种选择.有一两件事可以在Windows下做结束WaitCommEvent(),这是调用CancelSynchronousIo()函数,这将结束您的WaitCommEvent(),但要注意这可能是设备相关.CancelSynchronousIo()的主要问题是Windows CE也不支持它,所以你运气不好用于解决这个问题!
你是怎么做到的?事实是,要解决此问题,您根本无法使用WaitCommEvent(),因为无法在Windows CE支持的Windows上终止此功能.然后,您将使用ReadFile(),它会在读取NON OVERLAPPED I/O时再次阻塞,这将与Comm Timeouts一起使用.
使用ReadFile()和COMMTIMEOUTS结构意味着您必须有一个紧密循环等待您的串行数据,但如果您没有收到大量的串行数据,它应该不是问题.此外,以小超时结束循环的事件也将确保将资源传递回系统,并且您不会将处理器置于100%负载下.以下是我提出的解决方案,如果您认为可以改进,我会很感激您的反馈意见.
typedef struct
{
UINT8 sync;
UINT8 op
UINT8 dev;
UINT8 node;
UINT8 data;
UINT8 csum;
} COMMDAT;
COMSTAT cs = {0};
DWORD byte_count;
COMMDAT cd;
ZeroMemory(&cd, sizeof(COMMDAT));
bool recv = false;
do
{
ClearCommError(comm_handle, 0, &cs);
if (cs.cbInQue …
Run Code Online (Sandbox Code Playgroud) 我明确地在类定义中有朋友并且使它更清楚,删除了实现代码等...
class Ref
{
public:
Ref(char* s, size_t l) : _s(s), _l(l) {}
private:
char* _s;
size_t _l;
};
class foo
{
public:
friend stringstream& operator>>(std::stringstream& s, uint8_t& v) { return s; }
friend stringstream& operator>>(std::stringstream& s, const Ref& r) { return s; }
private:
std::stringstream ss;
void example(void)
{
char b[256];
Ref r(b, sizeof(b));
uint8_t i;
ss >> i >> r; <------ Why do I get an error here?
ss >> r >> i; <------ But this one seems …
Run Code Online (Sandbox Code Playgroud) 我有以下类,方法签名如下:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
Run Code Online (Sandbox Code Playgroud)
在实现文件中,我有这个:
std::vector<std::string> Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Run Code Online (Sandbox Code Playgroud)
所以我想,让我们看看我是否可以通过一些自动魔法来简化这个功能签名,因为它会变成一个"满满一行"!所以我试过这个......
class Foo
{
public:
auto barResults(const std::vector<std::string>&, const std::vector<std::string>&);
}
auto Foo::barResults(const std::vector<std::string>& list1, const std::vector<std::string>& list2)
{
std::vector<std::string> results;
// small amount of implementation here...
return results;
}
Run Code Online (Sandbox Code Playgroud)
现在忽略了这样一个事实:是的,我可以使用"使用命名空间std"来修剪它,我想知道为什么编译器给了我一个错误"返回'auto'的函数在定义之前不能使用".
我个人原本会认为编译器很容易推断出该方法的返回类型,但在这种情况下它似乎并非如此.当然,您可以使用尾随返回类型修复它,如下所示:
class Foo
{
public:
std::vector<std::string> barResults(const std::vector<std::string>&, const std::vector<std::string>&) -> std::vector<std::string>;
}
Run Code Online (Sandbox Code Playgroud)
但是如果你使用上面的话,那就不比以前好了.因此,除了"使用命名空间std"之外,有没有更好的方法来执行上述操作,为什么编译器不能在此实例中推断出返回类型?或者甚至,它是否依赖于如何调用此方法导致编译器无法确定返回类型.