小编tmy*_*ebu的帖子

在C中除以零和未定义的行为

本文中,以下是一段可以触发除零的代码示例:

if (arg2 == 0)
    ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO),
                    errmsg("division by zero")));
/* No overflow is possible */
PG_RETURN_INT32((int32) arg1 / arg2);
Run Code Online (Sandbox Code Playgroud)

ereport这是一个宏,它扩展为对 - bool返回函数的调用,该函数errstart可能会或可能不会返回,并且?:对其返回值有条件(使用a ),调用另一个函数.在这种情况下,我认为ereport水平ERROR无条件地导致longjmp()其他地方.

因此,对上述代码的简单解释是,如果arg2非零,则将发生除法并返回结果,而如果arg2为零,则将报告错误并且不会发生除法.然而,链接的论文声称C编译器可以在零检查之前合法地提升除法,然后推断零检查从未被触发.他们唯一的推理似乎是不正确的

程序员没有通知编译器对ereport的调用(ERROR,:: :)没有返回.这意味着除法将始终执行.

John Regehr有一个更简单的例子:

void bar (void);
int a;
void foo3 (unsigned y, unsigned z)
{
  bar();
  a = y%z;
}
Run Code Online (Sandbox Code Playgroud)

根据这篇博文,clang在调用之上提升了模运算bar,并且他展示了一些汇编代码来证明它.

我对C的理解是适用于这些片段的

  1. 没有或不可以返回的函数在标准C中是格式良好的,并且这样的声明不需要特定的属性,钟声或哨声.

  2. 调用不返回或不返回的函数的语义是明确定义的,特别是通过C99中的6.5.2.2"函数调用".

  3. 由于ereport调用是一个完整的表达式,因此有一个序列点;.类似地,由于barJohn Regehr的代码中的调用是一个完整的表达式,因此在该处有一个序列点 …

c undefined-behavior language-lawyer

13
推荐指数
1
解决办法
517
查看次数

Bellman Ford和Dijkstra算法之间的区别

   2           1
1----------2---------4
|          |         |
|3         |3        |1
|    6     |         |
3---------5 ---------
Run Code Online (Sandbox Code Playgroud)

好的,这就是图表.我的源节点是1和目标节点5

我的问题是.

算法是否会提供相同的输出?也就是说,双方都会回归1->2->4->5吗?(除非在dijkstra中不允许负权重)

在此先感谢您的帮助.

networking graph-algorithm

12
推荐指数
1
解决办法
4万
查看次数

是否有一种有效的方法来计算给定线段之间的交叉点数量?

假设我在一般位置有n个线段.对于我的每个n段,我如何快速计算它相交的其他n-1的数量?

我可以在O(n 2)时间内天真地做这件事.我可以在O((n + k)log n)时间内使用相当简单的扫描线算法(Bentley-Ottmann)找到所有交叉点,其中k是这样的交叉点的数量,然后将我发现的交叉点聚合成一堆计数.

不过,我不需要找到交叉路口; 我只是想知道有多少.我没有看到如何将扫描线算法修改得更快,因为它需要为每个交叉点重新排序树中的两个东西,我想不出任何其他没有遇到同样问题的技术.

我也有兴趣听听如何计算总交叉口数量.

language-agnostic algorithm geometry computational-geometry

8
推荐指数
1
解决办法
1905
查看次数

编写符合严格别名的memcpy符合条件

在询问"如何实现符合严格别名规则的memcpy函数"时,一般的答案就是这样的

void *memcpy(void *dest, const void *src, size_t n)
{
    for (size_t i = 0; i < n; i++)
        ((char*)dest)[i] = ((const char*)src)[i];
    return dest;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我理解正确的话,编译器可以自由地重新排序对memcpy的调用并访问dest,因为它可以使用任何其他指针类型的读取重新排序写入char*(严格的别名规则阻止仅对char*的读取进行重新排序)到任何其他指针类型).

这是正确的,如果是的话,有没有办法正确实现memcpy,还是我们应该依赖内置的memcpy?

请注意,这个问题不仅涉及memcpy,还涉及任何反序列化/解码功能.

c c++ strict-aliasing memcpy

8
推荐指数
2
解决办法
1387
查看次数

C++ 11中的数据竞争,UB和计数器

以下模式在许多软件中很常见,这些软件想告诉用户它做了多少事情:

int num_times_done_it; // global

void doit() {
  ++num_times_done_it;
  // do something
}

void report_stats() {
  printf("called doit %i times\n", num_times_done_it);
  // and probably some other stuff too
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果多个线程可以在doit没有某种同步的情况下调用,则并发读取 - 修改 - 写入num_times_done_it可能是数据争用,因此整个程序的行为将是未定义的.此外,如果report_stats可以在doit没有任何同步的情况下同时调用,则在线程修改num_times_done_it和报告其值的线程之间存在另一个数据争用.

通常,程序员只想要doit尽可能少的开销来调用大多数正确的次数.

(如果你认为这个例子是微不足道的,Hogwild!比使用基本上这个技巧的数据无竞争随机梯度下降获得了显着的速度优势.而且,我相信Hotspot JVM正是这种无人看守,多线程访问共享计数器对于方法调用计数---虽然它是明确的,因为它生成汇编代码而不是C++ 11.)

明显的非解决方案:

  • 原子论,我所知道的任何内存顺序,在这里"尽可能少的开销"失败(原子增量可能比普通增量贵得多),而在"大多数正确"(通过完全正确)过度交付.
  • 我不相信折腾volatile到组合,使数据的比赛好了,更换的声明num_times_done_itvolatile int num_times_done_it不能解决任何事情.
  • 有一个尴尬的解决方案,每个线程有一个单独的计数器,并将它们全部添加report_stats,但这并不能解决doit和之间的数据竞争report_stats.此外,它很乱,它假设更新是关联的,并不真正适合Hogwild!的用法.

是否有可能在一个非平凡的多线程C++ 11程序中实现具有良好定义语义的调用计数器,而无需某种形式的同步?

编辑:似乎我们可以使用memory_order_relaxed以下方式稍微间接地执行此操作:

atomic<int> num_times_done_it;
void doit() …
Run Code Online (Sandbox Code Playgroud)

c++ multithreading memory-model c++11

6
推荐指数
1
解决办法
712
查看次数

在C++中对f(g(),h())的评估顺序

这是对C++实现的一种后续行为,理论上可以并行化两个函数参数的评估吗?

假设我有以下C++ 11程序:

#include <cstdio>
using std::printf;
int g() { printf("1\n"); printf("3\n"); return 2; }
int h() { printf("2\n"); printf("4\n"); return 3; }
void f(int a, int b) { printf("%i\n", a+b); }
int main() { f(g(), h()); }
Run Code Online (Sandbox Code Playgroud)

当然可以观察到以下输出:

1 3 2 4 5
2 4 1 3 5
Run Code Online (Sandbox Code Playgroud)

1 2 3 4 5怎么样?

(据我所知,唯一的限制是1在3之前测序,2在4之前测序,3和4在5之前测序)

c++ language-lawyer c++11

4
推荐指数
1
解决办法
258
查看次数

如何在黄瓜中链接特征和步骤定义

我是Cucumber java的新手,并且在初始阶段存在此问题:由于某种原因,我没有使用MAVEN项目。我刚刚在eclipse中创建了一个简单的Java项目。

我的功能位于“ src / dummy / pkg / features”下,我的实现“ StepDef.java”位于“ src / dummy / pkg / features / implementation”下

我已经为“给定”,“何时”和“然后”编写了步骤定义,但是当我运行功能文件时,它无法识别实现。如何将功能与步骤定义链接?

java cucumber cucumber-jvm cucumber-junit

3
推荐指数
1
解决办法
2万
查看次数

如果我在x86_64上使用gcc 4.9,__ float128到底是什么?

我写了一个简单的程序,以为我可以从反汇编中找到:

int main() {
  double a, b, c;
  scanf("%lf %lf %lf", &a, &b, &c);
  __float128 foo = a;
  foo += b; foo += c;
  printf("%f\n", (double)foo);
}
Run Code Online (Sandbox Code Playgroud)

main 编译(-O3)为以下内容:

  400630:       48 83 ec 38             sub    $0x38,%rsp
  400634:       bf 34 08 40 00          mov    $0x400834,%edi
  400639:       31 c0                   xor    %eax,%eax
  40063b:       48 8d 4c 24 28          lea    0x28(%rsp),%rcx
  400640:       48 8d 54 24 20          lea    0x20(%rsp),%rdx
  400645:       48 8d 74 24 18          lea    0x18(%rsp),%rsi
  40064a:       e8 c1 ff ff ff          callq …
Run Code Online (Sandbox Code Playgroud)

c++ floating-point gcc

3
推荐指数
1
解决办法
867
查看次数

为什么在哈希中的主聚类上下文中,接下来填充 i 个满槽的空槽的概率是 (i + 1)/m?

为什么在使用开放寻址作为冲突解决技术和线性探测的散列中的主聚类上下文中,接下来填充 i 个满槽的空槽的概率是 (i + 1)/m?这是算法简介 CLRS 的摘录“占用槽的长运行会累积,增加平均搜索时间。簇的出现是因为前面有 i 个满槽的空槽接下来会以 (i + 1)/m 的概率填充。长运行占用的槽位往往会变长,平均搜索时间也会增加。” 请帮忙。

algorithm hash

1
推荐指数
1
解决办法
1380
查看次数