鉴于此代码:
#include <string.h>
int equal4(const char* a, const char* b)
{
return memcmp(a, b, 4) == 0;
}
int less4(const char* a, const char* b)
{
return memcmp(a, b, 4) < 0;
}
Run Code Online (Sandbox Code Playgroud)
x86_64上的GCC 7引入了第一种情况的优化(Clang已经做了很长时间):
mov eax, DWORD PTR [rsi]
cmp DWORD PTR [rdi], eax
sete al
movzx eax, al
Run Code Online (Sandbox Code Playgroud)
但第二种情况仍然是memcmp():
sub rsp, 8
mov edx, 4
call memcmp
add rsp, 8
shr eax, 31
Run Code Online (Sandbox Code Playgroud)
是否可以对第二种情况应用类似的优化?什么是最好的装配,有没有明确的理由为什么它没有完成(由GCC或Clang)?
在Godbolt的Compiler Explorer上看到它:https://godbolt.org/g/jv8fcf
以下是我声称完成同样事情的两个功能:
bool fast(int x)
{
return x & 4242;
}
bool slow(int x)
{
return x && (x & 4242);
}
Run Code Online (Sandbox Code Playgroud)
从逻辑上讲,他们做同样的事情,只是为了100%肯定我写了一个测试,通过他们两个运行所有40亿个可能的输入,并且他们匹配.但汇编代码是一个不同的故事:
fast:
andl $4242, %edi
setne %al
ret
slow:
xorl %eax, %eax
testl %edi, %edi
je .L3
andl $4242, %edi
setne %al
.L3:
rep
ret
Run Code Online (Sandbox Code Playgroud)
令我感到惊讶的是,GCC无法实现消除冗余测试的逻辑上的飞跃.我用-O2,-O3和-Os尝试了g ++ 4.4.3和4.7.2,所有这些都生成了相同的代码.该平台是Linux x86_64.
有人可以解释为什么GCC不够聪明,不能在两种情况下生成相同的代码吗?我还想知道其他编译器是否可以做得更好.
编辑以添加测试工具:
#include <cstdlib>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
// make vector filled with numbers starting from argv[1]
int seed = atoi(argv[1]);
vector<int> v(100000); …Run Code Online (Sandbox Code Playgroud) 这与之前的问题类似,但那里的答案不能满足我的需求,我的问题略有不同:
我目前对一些包含排序数据的非常大的文件使用gzip压缩.当文件未被压缩时,二进制搜索是支持在排序数据中寻找位置的便捷有效方式.
但是当文件被压缩时,事情变得棘手.我最近发现了zlib的Z_FULL_FLUSH选项,可以在压缩过程中使用它在压缩输出中插入"同步点"(inflateSync()然后可以从文件中的各个点开始读取).这是可以的,虽然我已经拥有的文件必须重新压缩才能添加此功能(奇怪的gzip是没有这个选项,但如果必须,我愿意编写自己的压缩程序).
从一个来源看来,即使Z_FULL_FLUSH不是一个完美的解决方案......不仅所有gzip档案都不支持它,而且在档案中检测同步点的想法可能会产生误报(或者与同步的幻数重合)点,或由于Z_SYNC_FLUSH也产生同步点但它们不能用于随机访问的事实.
有更好的解决方案吗?如果可能的话,我想避免使用辅助文件进行索引,并且对准随机访问的显式默认支持将是有帮助的(即使它是大粒度的 - 就像能够以每10 MB的间隔开始读取一样).是否有另一种压缩格式比gzip更好地支持随机读取?
编辑:正如我所提到的,我希望在压缩数据中进行二进制搜索.我不需要寻找特定的(未压缩的)位置 - 只是在压缩文件中寻找一些粗粒度.我只是希望能够支持诸如"将数据从大约50%(25%,12.5%等)开始压缩到此压缩文件中".
如果我在向量上使用.reserve(items),向量将分配足够的内存来猜测我需要的项目数.
如果我以后使用.clear(),那么只清除向量还是保存我之前定义的保留?
谢谢.
这是我的代码:
int f(double x)
{
return isnan(x);
}
Run Code Online (Sandbox Code Playgroud)
如果我#include <cmath>得到这个集会:
xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
Run Code Online (Sandbox Code Playgroud)
这是相当聪明的:如果x与其自身的比较是无序的,则ucomisd设置奇偶校验标志,意味着x是NAN.然后setp将奇偶校验标志复制到结果中(只有一个字节,因此最初清除%eax).
但是,如果我#include <math.h>得到这个集会:
jmp __isnan
Run Code Online (Sandbox Code Playgroud)
现在代码不是内联的,并且__isnan函数当然没有更快的ucomisd指令,所以我们已经跳过没有任何好处.如果我将代码编译为C,我会得到同样的东西.
现在如果我将isnan()调用更改为__builtin_isnan(),我会得到简单的ucomisd指令指令,无论我包含哪个头,它也可以在C中工作.同样,如果我只是return x != x.
所以我的问题是,为什么C <math.h>头提供的效率isnan()低于C++ <cmath>头?人们真的希望使用__builtin_isnan(),如果是,为什么?
我在x86-64上使用-O2和-O3优化测试了GCC 4.7.2和4.9.0 .
我正在尝试使用mysqldump转储模式,它主要起作用,但我遇到了一个好奇心:-p或者--password选项似乎正在做除了设置密码之外的其他事情(因为man页面和--help输出说它应该).
具体来说,看起来它正在执行此处指示的内容:http://snippets.dzone.com/posts/show/360 - 即将数据库设置为dump.
为了支持我有点古怪的主张,我可以告诉你,如果我没有指定--password(或-p)选项,该命令将打印用法语句并退出并显示错误.如果我确实指定了它,我会立即提示输入密码(!),然后--password转储选项中指定的数据库(或者在通常情况下给出的错误是指定了与任何数据库名称不匹配的密码).
这是一个成绩单:
$ mysqldump -u test -h myhost --no-data --tables --password lose
Enter password:
-- MySQL dump 10.10
mysqldump: Got error: 1044: Access denied for user 'test'@'%' to
database 'lose' when selecting the database
那么,是什么给出的?这是应该的方式吗?它肯定似乎没有意义,也不符合官方文档.最后,如果这只是它的工作方式,我是如何指定在自动化作业中使用的密码?使用expect???
我正在使用mysqldump Ver 10.10 Distrib 5.0.22, for pc-linux-gnu (i486).
我在node.js中运行它:
> x = { 'foo' : 'bar' }
{ foo: 'bar' }
> console.log(x)
{ foo: 'bar' }
undefined
> console.log("hmm: " + x)
hmm: [object Object]
undefined
Run Code Online (Sandbox Code Playgroud)
我不明白的是为什么console.log(x)"漂亮地打印"对象,而字符串连接"丑陋打印"它.更重要的是,什么是打印的最佳方式hmm: { foo: 'bar' }?
我想编写一个从未真正产生任何东西的Python生成器函数.基本上它是一个"无所事事"的插件,可以被其他代码用来调用生成器(但并不总是需要它的结果).到目前为止我有这个:
def empty_generator():
# ... do some stuff, but don't yield anything
if False:
yield
Run Code Online (Sandbox Code Playgroud)
现在,这可行,但我想知道是否有更具表现力的方式来说同样的事情,即声明一个函数是一个生成器,即使它从不产生任何值.我上面使用的技巧是在我的函数中显示Python一个yield语句,即使它无法访问.
以下是荒谬的,但编译干净g++ -Wall -Wextra -Werror -Winit-self(我测试了GCC 4.7.2和4.9.0):
#include <iostream>
#include <string>
int main()
{
for (int ii = 0; ii < 1; ++ii)
{
const std::string& str = str; // !!
std::cout << str << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
标记的行!!导致未定义的行为,但未由GCC诊断.然而,评论出这for条线让GCC抱怨:
error: ‘str’ is used uninitialized in this function [-Werror=uninitialized]
Run Code Online (Sandbox Code Playgroud)
我想知道:为什么海湾合作委员会这么容易被愚弄?当代码不在循环中时,GCC知道它是错误的.但是将相同的代码放在一个简单的循环中,GCC不再理解了.这困扰我,因为我们依靠相当多的编译器,当我们在C++中做出愚蠢的错误通知我们的,但它没有一个看似微不足道的情况.
奖金琐事:
std::string到int 并打开优化,GCC将诊断错误甚至与循环.-O3,GCC会逐字地调用带有字符串参数的空指针的ostream插入函数.如果您认为如果您没有进行任何不安全的转换,那么您可以安全地使用空引用,请再想一想.我已经为此提交了一个GCC错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id = 63203 - 我仍然希望更好地了解出现了什么问题以及它可能如何影响类似诊断的可靠性.
我有一系列POD结构,我试图在一个字段中求和.这是一个最小的例子:
struct Item
{
int x = 0;
int y = 0;
};
typedef Item Items[2];
struct ItemArray
{
Items items;
int sum_x1() const;
int sum_x2() const;
};
int ItemArray::sum_x1() const
{
int total = 0;
for (unsigned ii = 0; ii < 2; ++ii)
{
total += items[ii].x;
}
return total;
}
int ItemArray::sum_x2() const
{
int total = 0;
for (const Item& item : items)
{
total += item.x;
}
return total;
}
Run Code Online (Sandbox Code Playgroud)
两个sum函数做同样的事情.Clang以相同的方式编译它们.但是-O3在x86_64上的GCC 6 却没有.这是 …