有一天,我升级我的Windows从MSVC2013到MSVC2017和LO构建环境,不料,在我的计划已被多年工作正常功能(现在仍然工作在克细++ /铛)突然开始时MSVC2017编译给出不正确的结果.
我能够重写函数再次给出正确的结果,但是经验让我好奇 - 我的函数调用了未定义的行为(直到现在恰好给出了正确的结果),或者是代码定义明确且MSVC2017正在越野车?
下面是一个简单的程序,在重写之前和之后都显示了该功能的玩具版本.特别是,当使用值为-32762的参数调用时,函数maybe_invokes_undefined_behavior(),如下所示,调用未定义的行为吗?
#include <stdio.h>
enum {ciFirstToken = -32768};
// This function sometimes gives unexpected results under MSVC2017
void maybe_invokes_undefined_behavior(short token)
{
if (token >= 0) return;
token -= ciFirstToken; // does this invoke undefined behavior if (token==-32762) and (ciFirstToken==-32768)?
if (token == 6)
{
printf("Token is 6, as expected (unexpected behavior not reproduced)\n");
}
else
{
printf("Token should now be 6, but it's actually %i\n", (int) token); // under MSVC2017 this prints -65530 !?
}
} …Run Code Online (Sandbox Code Playgroud) 大约一周前,有人在StackOverflow上询问为什么他们用于连接到IPv6链接本地地址的Python代码无效,我回答说,因为它是一个链接本地地址,所以需要添加%en0(或者其他任何所需的local-interface-name是其目标IP地址的后缀.我以为我知道我在说什么,所以在回答之前我没有真正测试过我的建议(对我感到羞耻!).
今天我为自己使用了同样的技术,却发现它似乎不起作用.:^(也就是说,此代码不起作用:
>>> from socket import *
>>> s = socket(AF_INET6, SOCK_STREAM)
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in connect
socket.error: [Errno 65] No route to host
Run Code Online (Sandbox Code Playgroud)
另一方面,以下代码可以工作(带或不带%en0后缀):
>>> from socket import *
>>> s = socket(AF_INET6, SOCK_STREAM)
>>> s.connect(('fe80::21f:5bff:fe3f:1b36%en0', 2001, 0, 6))
>>>
Run Code Online (Sandbox Code Playgroud)
...但我不喜欢这样做,因为为了弄清楚要为最后一个参数提供哪个范围ID整数,我必须执行一堆不可移植的代码来迭代本地接口list,找到名为'en0'的接口,并提取其范围ID,这比我想要的更复杂.
鉴于connect()正在接受IP地址的%en0后缀,为什么不按预期使用它来确定范围ID?
FWIW,我正在使用MacOS/X 10.6.4下的Python 2.6.1进行测试.
注意:这个问题涉及堆栈溢出(认为无限递归),而不是缓冲区溢出.
如果我编写一个正确的程序,但是它接受来自Internet的输入来确定它调用的递归函数中的递归级别,那么这可能足以让某人破坏机器吗?
我知道有人可能通过导致堆栈溢出来崩溃进程,但是他们是否可以注入代码?或者c运行时是否检测到堆栈溢出情况并干净地中止?
只是好奇...
今天我正在追踪我的程序为什么会出现一些意外的校验和错配错误,在我编写的一些代码中,这些代码序列化和反序列化IEEE-754浮点值,格式包含32位校验和值(计算出来)通过在浮点数组的字节上运行CRC类型算法).
经过一番头疼之后,我意识到问题是0.0f和-0.0f分别有不同的位模式(0x00000000 vs 0x00000080(little-endian)),但它们被C++相等运算符认为是等价的.因此,校验和不匹配错误的发生是因为我的校验和计算算法选择了这两个位模式之间的差异,而我的代码库中的某些其他部分(使用浮点相等测试,而不是逐字节地查看值) byte)没有做出这种区分.
好吧,公平地说 - 无论如何,我应该知道比进行浮点平等测试更好.
但这让我想到,是否有其他IEEE-754浮点值被认为是相等的(根据C ==运算符)但是有不同的位模式?或者,换句话说,==运算符究竟是如何确定两个浮点值是否相等?新手虽然它在他们的位模式上做了类似memcmp()的事情,但显然它比那更细微.
这是我的意思的代码示例,如果上面我不清楚的话.
#include <stdio.h>
static void PrintFloatBytes(const char * title, float f)
{
printf("Byte-representation of [%s] is: ", title);
const unsigned char * p = (const unsigned char *) &f;
for (int i=0; i<sizeof(f); i++) printf("%02x ", p[i]);
printf("\n");
}
int main(int argc, char ** argv)
{
const float pzero = -0.0f;
const float nzero = +0.0f;
PrintFloatBytes("pzero", pzero);
PrintFloatBytes("nzero", nzero);
printf("Is pzero equal to nzero? %s\n", (pzero==nzero)?"Yes":"No");
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我有一个模板化的容器类,类似于这个玩具代码:
template <class ItemType> class MyVector
{
public:
MyVector() : _numItems(0), _items(NULL) {/* empty */}
/** Returns a reference to the first item in our array,
* or a default-constructed item if the array is empty.
*/
const ItemType & GetFirstItemWithDefault() const
{
return (_numItems > 0) ? _items[0] : _defaultItem;
}
[other methods omitted because they aren't relevant]
private:
int _numItems; // how many valid items (_items) points to
ItemType * _items; // demand-allocated
const ItemType _defaultItem;
};
Run Code Online (Sandbox Code Playgroud)
这个类非常方便使用 …
我今天得到了一个C++类型安全问题,我想知道是否有一个很好的方法让编译器在编译时检测到这个问题.考虑这个示例代码:
class Bar
{
public:
void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20)
{
[...]
}
};
int main(int argc, char ** argv)
{
int x = 40, y = 50;
Bar b;
b.Foo(); // correct usage
b.Foo(true, x, y); // correct usage
b.Foo(x, y); // problem: compiles but won't do what the caller expects
}
Run Code Online (Sandbox Code Playgroud)
正如对b.Foo()的最后调用所示,问题在于很容易忘记提供第一个参数,并且在这种情况下,事情会以一种未被编译器捕获的方式出错.
如果我能让编译器说"ERROR,非布尔值被提供给布尔参数",那会更好.这将迫使开发人员检查代码,如果他真的想要传入x作为布尔值,他必须传入(x!= 0).
这似乎是使用"explicit"关键字的好地方,但AFAICT该关键字不适用于函数参数.
(我意识到可以通过不为参数提供默认值来避免这种问题,但默认值可以非常方便)
我今天正在尝试Windows对条件变量的支持(由微软为Windows Vista及更高版本提供).要初始化一个条件变量,我调用InitializeConditionVariable(),这很简单,但是当我使用它时,我没有看到任何方法来破坏条件变量.为什么没有DeleteConditionVariable()函数?
(我希望API类似于现有的CreateCriticalSection()/ DestroyCriticalSection()API)
我在这里为bash脚本专家提供了一些小问题...我有一个bash脚本,需要在运行时创建一个小的(80字节)二进制文件.文件的内容需要包含在脚本本身内(即我不想只是将文件与脚本一起打包).
我的脚本目前这样做:
echo 'begin-base64 644 dummy.wav' > /tmp/dummy.uu
echo 'UklGRkgAAABXQVZFZm10IBAAAAADAAEAAHcBAADcBQAEACAAZmFjdAQAAAAAAAAAUEVBSxAAAAAB' >> /tmp/dummy.uu
echo 'AAAAQDYlTAAAAAAAAAAAZGF0YQAAAAA=' >> /tmp/dummy.uu
echo '====' >> /tmp/dummy.uu
uudecode -o /tmp/dummy.wav /tmp/dummy.uu
rm /tmp/dummy.uu
Run Code Online (Sandbox Code Playgroud)
...在上面的运行之后,我有我的文件/tmp/dummy.wav.但我刚刚发现这个脚本运行的计算机没有安装uudecode(我不允许安装它),所以我需要找到一些其他的方法来创建这个文件.有任何想法吗?
我有一些代码,我已成功使用多年来实现"变体类型对象"; 也就是说,一个C++对象可以保存各种类型的值,但只使用(大约)尽可能多的内存作为最大的可能类型.该代码在精神上类似于tagged-union,但它也支持非POD数据类型.它通过使用char缓冲区,placement new/delete和reinterpret_cast <>来实现这种魔力.
我最近尝试在gcc 4.4.3(带-O3和-Wall)下编译这段代码,并得到了很多这样的警告:
warning: dereferencing type-punned pointer will break strict-aliasing rules
Run Code Online (Sandbox Code Playgroud)
从我读过的内容来看,这表明gcc的新优化器可能会生成'buggy'代码,我显然希望避免这种代码.
我在下面粘贴了我的代码的"玩具版"; 我可以对我的代码做些什么来使它在gcc 4.4.3下更安全,同时仍然支持非POD数据类型?我知道作为最后的手段,我总是可以使用-fno-strict-aliasing编译代码,但是如果代码在优化下没有中断会更好,所以我宁愿不这样做.
(注意,我想避免在代码库中引入boost或C++ 0X依赖,所以虽然boost/C++ 0X解决方案很有趣,但我更喜欢更老式的东西)
#include <new>
class Duck
{
public:
Duck() : _speed(0.0f), _quacking(false) {/* empty */}
virtual ~Duck() {/* empty */} // virtual only to demonstrate that this may not be a POD type
float _speed;
bool _quacking;
};
class Soup
{
public:
Soup() : _size(0), _temperature(0.0f) {/* empty */}
virtual ~Soup() {/* empty */} // virtual only to demonstrate that this …Run Code Online (Sandbox Code Playgroud) 我正在努力为我的服务器程序添加OpenSSL支持,并且通常它工作得很好,但我遇到了一个问题.
首先,一些背景知识:服务器是单线程的,使用非阻塞I/O和select()循环来同时处理多个客户端.服务器链接到libssl.0.9.8.dylib和lib crypto.0.9.8.dylib(即MacOS/X 10.8.5在/ usr/lib中提供的库).客户端< - >服务器协议是专有的全双工消息传递协议; 也就是说,客户端和服务器都可以随时发送和接收数据,并且客户端< - >服务器TCP连接无限期地保持连接(即直到客户端或服务器决定断开连接).
问题是:我的客户端可以连接到服务器,发送和接收数据工作正常(现在我已经整理了SSL_ERROR_WANT_WRITE和SSL_ERROR_WANT_READ逻辑)...但是如果服务器接受()'是新客户端连接而其他客户端在发送或接收数据的过程中,SSL层似乎破裂了.特别是,在服务器运行SetupSSL()例程(如下所示)以设置新接受的套接字之后,在一个或多个其他(预先存在的)客户端套接字上的SSL_read()将立即返回-1,并且ERR_print_errors_fp(stderr)给出了这个输出:
SSL_read() ERROR: 5673:error:140F3042:SSL routines:SSL_UNDEFINED_CONST_FUNCTION:called a function you should not call:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/ssl_lib.c:2248:
Run Code Online (Sandbox Code Playgroud)
首次出现此错误后,服务器很大程度上停止工作.数据移动停止,如果我尝试连接另一个客户端,我经常会收到此错误:
SSL_read() ERROR: 5673:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_srvr.c:578:
Run Code Online (Sandbox Code Playgroud)
在我的测试场景中,这种情况大约占25%.如果我确保在新客户端连接时我的预先存在的客户端连接是空闲的(没有数据被发送或接收),它永远不会发生.有谁知道这里可能出了什么问题?我找到了一个OpenSSL错误,还是有一些我忽略的细节?我的程序中的一些相关代码粘贴在下面,以防它有用.
// Socket setup routine, called when the server accepts a new TCP socket
int SSLSession :: SetupSSL(int sockfd)
{
_ctx = SSL_CTX_new(SSLv23_method());
if (_ctx)
{
SSL_CTX_set_mode(_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
_ssl = SSL_new(_ctx);
if (_ssl)
{
_sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
if (_sbio)
{
SSL_set_bio(_ssl, _sbio, _sbio);
SSL_set_accept_state(_ssl);
BIO_set_nbio(_sbio, !blocking);
ERR_print_errors_fp(stderr);
return RESULT_SUCCESS;
} …Run Code Online (Sandbox Code Playgroud)