小编Grz*_*ski的帖子

GCC是否为静态分支预测生成次优代码?

从我的大学课程中,我听说,按照惯例,最好放置更多可能的条件if而不是in else,这可能有助于静态分支预测器.例如:

if (check_collision(player, enemy)) { // very unlikely to be true
    doA();
} else {
    doB();
}
Run Code Online (Sandbox Code Playgroud)

可以改写为:

if (!check_collision(player, enemy)) {
    doB();
} else {
    doA();
}
Run Code Online (Sandbox Code Playgroud)

我发现了一篇博客文章分支模式,使用GCC,它更详细地解释了这种现象:

为if语句生成前向分支.使它们不可能被采用的基本原理是处理器可以利用分支指令之后的指令可能已经被放置在指令单元内的指令缓冲器中的事实.

旁边,它说(强调我的):

在编写if-else语句时,总是使"then"块比else块更可能被执行,因此处理器可以利用已经放在指令获取缓冲区中的指令.

最终,有一篇由英特尔,分支和循环重组编写的文章,以防止错误预测,其中总结了两个规则:

当微处理器遇到分支时没有收集数据时使用静态分支预测,这通常是第一次遇到分支.规则很简单:

  • 正向分支默认不采用
  • 向后分支默认采用

为了有效地编写代码以利用这些规则,在编写if-elseswitch语句时,首先检查最常见的情况,然后逐步处理最不常见的情况.

据我所知,这个想法是流水线CPU可以遵循指令缓存中的指令,而不会通过跳转到代码段内的另一个地址来破坏它.但是,我知道,在现代CPU微体系结构的情况下,这可能会过于简单化.

但是,看起来GCC不尊重这些规则.鉴于代码:

extern void foo();
extern void bar();

int some_func(int n)
{
    if (n) {
        foo();
    }
    else {
        bar();
    }
    return 0; …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly gcc branch-prediction

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

PostgreSQL行排序为NULL值,最后为空字符串

我使用了以下SQL,它工作正常,但我也需要对空字符串进行排序.请给我指导.

SELECT id, first_name, last_name 
FROM users
ORDER BY first_name DESC NULLS LAST
limit 10;
Run Code Online (Sandbox Code Playgroud)

postgresql

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

realloc(p,0)真的涉及glibc中的free(p)吗?

我发现有些人和像图书这样的参考文献表明,如果p != NULLp来自之前的分配(例如by malloc),则realloc(p, 0)相当于free(p)GNU/Linux.为了支持这一论点,man realloc完全以这种方式陈述(强调我的前进):

realloc()函数将ptr指向的内存块的大小更改为size字节.内容将在从区域开始到新旧尺寸的最小范围内保持不变.如果新大小大于旧大小,则不会初始化添加的内存.如果ptr为NULL,则对于所有size值,调用等效于malloc(size); 如果size等于零,并且ptr不为NULL,则该调用等效于free(ptr).除非ptr为NULL,否则必须由之前调用malloc(),calloc()或realloc()返回.如果指向的区域被移动,则完成自由(ptr).

正如您在此问题中所发现的那样,C标准没有准确定义应该发生什么,实际行为是实现定义的.进一步来说:

C11§7.22.3/ p1 内存管理功能说:

如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象.

和C11§7.22.3.5realloc 函数包含:

3)(...)如果无法分配新对象的内存,则不会释放旧对象,并且其值不变.

4)该realloc函数返回指向新对象的指针(可能与指向旧对象的指针具有相同的值),如果无法分配新对象,则返回空指针.

我写了一些基本代码mcheck,通过内存检查器的帮助找出实际行为,提供了glibc:

#include <mcheck.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int a = 5;
    int *p, *q;

    mtrace();

    p = malloc(sizeof(int));
    q = &a;

    printf("%p\n", (void *) p);
    printf("%p\n", (void *) …
Run Code Online (Sandbox Code Playgroud)

c glibc language-lawyer

21
推荐指数
2
解决办法
1083
查看次数

推荐的方法来跟踪C程序中数组越界访问/写入

考虑在C中编写一些不那么明显的算法的实现.例如,让我们在KN King的"C编程:现代方法,第2版"一书中找到它的递归快速排序,它可以从这里获得.最有趣的部分包括以下两个定义:

void quicksort(int a[], int low, int high)
{
    int middle;

    if (low >= high)
        return;

    middle = split(a, low, high);
    quicksort(a, low, middle - 1);
    quicksort(a, middle + 1, high);
}

int split(int a[], int low, int high)
{
    int part_element = a[low];

    for (;;) {
       while (low < high && part_element <= a[high])
           high--;
       if (low >= high)
           break;
       a[low++] = a[high];

       while (low < high && a[low] <= part_element)
           low++;
       if (low >= high) …
Run Code Online (Sandbox Code Playgroud)

c gdb splint memcheck cppcheck

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

使用goto语句强制for循环的至少一次迭代的有效性

免责声明:我知道这是模糊的,我不会这样编程.我知道首选的do-while陈述,而不是那个,问题更多的是关于特定语言结构的有效性.


goto始终应该忽略条件表达式中的for循环?从我观察到它跳过第一个(即初始化)和第二个表达式.这总是会以这种方式发生,还是纯粹依赖于编译器?

#include <stdio.h>

int main(void)
{
    int m = 5;

    goto BODY;
    for (m = 0; m < 5; m++)
        BODY: puts("Message"); // prints "Message" once

    printf("m = %d\n", m); // prints m = 6

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

c goto language-lawyer

20
推荐指数
2
解决办法
1108
查看次数

为什么不匹配的原型和定义与空参数列表在GCC和Clang中给出不同的结果?

给定(简化)代码片段:

void foo(int a, int b); // declaration with prototype

int main(void)
{
    foo(1, 5); // type-checked call (i.e. because of previous prototype)
    return 0;
}

void foo() // old-style definition (with empty argument list)
{

}
Run Code Online (Sandbox Code Playgroud)

和命令行选项(但是,因为我检查它们并不重要):

-x c -std=c11 -pedantic -Wall
Run Code Online (Sandbox Code Playgroud)

gcc 7.2无法编译它,并显示以下错误消息:

错误:参数数量与原型不匹配

虽然clang 4.0翻译它没有任何投诉.

根据C标准,哪种实施方法是正确的?旧式定义"取消"以前的原型是否有效?

c language-lawyer c11

17
推荐指数
4
解决办法
1299
查看次数

在C89(又名ANSI C)中省略return语句未定义的行为?

考虑以下基本示例:

#include <stdio.h>

int main(void)
{
    printf("Hi there!\n");
}
Run Code Online (Sandbox Code Playgroud)

它是否在C89中调用未定义的行为?我试图从这个问题中得到一些意义,但是大多数赞成的答案声称它是实现定义的,绝对没有UB(与Keith Thompson的评论,看起来相互矛盾).

规范在§3.16 定义和惯例中说明:

如果违反约束之外出现的"应"或"不应"要求.行为未定义.未定义的行为在本国际标准中以"未定义的行为" 或省略任何明确的行为定义来表示.这三者之间的重点没有区别:它们都描述了"未定义的行为".

和§5.1.2.2.3 程序终止:

从初始调用到main函数的返回等效于使用exit函数返回的值main作为其参数调用函数.如果main函数执行不指定值的返回,则返回到主机环境的终止状态是未定义的.

我的理解是,后面的子条款不包括丢失返回的情况,因为return声明从未被调用过,因此以前的子条款适用.

然而futher读数表明不同的东西,§6.6.6.4 return声明:

如果执行了return没有表达式的语句,并且调用者使用了函数调用的值,则行为是未定义的. 到达}那个终止函数等同于执行return没有表达式的 语句.

好的,所以现在的5.1.2.2.3子条款适用:

如果main函数执行不指定值的返回.返回到主机环境的终止状态是未定义的.

术语"终止状态未定义"似乎不是UB,也不是任何特定行为,但更像是在C标准范围之外,更像是:"让主机环境变得烦恼,我们洗手这里".这是正确的解释吗?

c c89 language-lawyer

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

用户"postgres"的密码验证失败

我在CentOS服务器上成功安装了PostgreSQL服务器8.4.之后,我使用'postgres'用户登录CentOS服务器,但我无法运行任何命令,出现错误:

用户"postgres"的密码验证失败

以下是pg_hba.conf和postgresql.conf中的一些配置:

--------------------configuration in postgresql.conf-----------
listen_addresses = '*'

--------------------configuration in pg_hba.conf---------------
local   all         all                               md5  
local   all         postgres                          md5 
host    all         all         127.0.0.1/32          md5  
host    all         all         ::1/128               md5
Run Code Online (Sandbox Code Playgroud)

database postgresql

14
推荐指数
3
解决办法
5万
查看次数

C++中的条件表达式是否总是bool类型?

在C面向条件运营商求值10类型的int(即使它确实有专用_Bool型).参考C11 N1570草案:

C11§6.5.8/ 6 关系运算符

如果指定的关系为真,则每个运算符<(小于),>(大于),<=(小于或等于)和>=(大于或等于)将产生1,如果为假,则为0.107)结果有类型int.

C11§6.5.9/ 3 平等运营商

==(等于)和!=(不等于)运算符类似于除了它们的优先级低的关系运算符.108)如果指定的关系为真,则每个运算符产生1,如果为假,则产生0.结果有类型int.对于任何一对操作数,其中一个关系是正确的.

C11 6.5.13/3 逻辑AND运算符

&&运营商将产生1,如果两个操作数的比较不等于0; 否则,它产生0.结果有类型int.

C11 6.5.14/3 逻辑OR运算符

||操作人员应得到1如果任一操作数的比较不等于0; 否则,它产生0.结果有类型int.

正如我检查的那样,C++似乎在这个问题上有所不同,如下面的示例所示(请参阅http://ideone.com/u3NxfW):

#include <iostream>
#include <typeinfo>

int main() {
    double x = 10.0;

    std::cout << typeid(x <= 10.0).name() << std::endl;

    return …
Run Code Online (Sandbox Code Playgroud)

c c++ language-lawyer c++11 c++03

14
推荐指数
2
解决办法
1005
查看次数

无符号和较大签名类型之间隐式转换的不一致行为

考虑以下示例:

#include <stdio.h>

int main(void)
{
    unsigned char a  = 15; /* one byte */
    unsigned short b = 15; /* two bytes */
    unsigned int c   = 15; /* four bytes */

    long x = -a; /* eight bytes */
    printf("%ld\n", x);

    x = -b;
    printf("%ld\n", x);

    x = -c;
    printf("%ld\n", x);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译我正在使用GCC 4.4.7(它没有给我任何警告):

gcc -g -std=c99 -pedantic-errors -Wall -W check.c
Run Code Online (Sandbox Code Playgroud)

我的结果是:

-15
-15
4294967281
Run Code Online (Sandbox Code Playgroud)

问题是为什么两者unsigned charunsigned short值都正确地"传播"到(签名)long,而unsigned int …

c c99 c89 integer-promotion implicit-conversion

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