C语言中的“限制”限定词是否可以帮助查找由于重叠块而引起的错误?

时间:2019-05-14 23:52:18

标签: c

在阅读了关键字restrict之后,我有点困惑。它似乎仅向编译器提示优化的可能性。但是寻找错误或提高语言的表达能力不是很多。

众所周知,过去的C程序员中有memcpy()memmove(),这两个中的后者承诺处理重叠区域,前者承诺不处理重叠区域。

现在,您可以在函数参数的结构中编写restrict关键字,并且只需使用指针声明即可单独使用。

但是我找不到任何解释,如果您的代码中包含这些应用程序的组合,那一切应该如何工作。

示例:

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define SUCCESS 1
#define FAILED 0

typedef int Ret_t;

Ret_t check( Ret_t result, const char * expr, int line, const char * file )
{
    if(FAILED == result)
        printf("Expr: %s failed! (%s:%d)\n", expr, file,line);
    return result;
}


#define CHECK(expr) (check(expr,#expr))
#define CHECK_ABORT(expr) if(FAILED == check((expr),#expr,__LINE__,__FILE__)) return FAILED
#define CHECK_ABORT_MAIN(expr) if(FAILED == check((expr),#expr,__LINE__,__FILE__)) return -1
#define ARRAY_CAPACITY(x) (sizeof(x) / sizeof((x)[0]))

typedef struct Slice_uint8_tag
{
    uint8_t * restrict p;
    size_t capacity;
} Slice_uint8_t;

typedef struct const_Slice_uint8_tag
{
    const uint8_t * restrict p;
    size_t size;
} const_Slice_uint8_t;

static inline
Slice_uint8_t
make_Slice_uint8 (uint8_t* restrict p,size_t capacity)
{
    Slice_uint8_t s = { .p = p, .capacity = capacity };
    return s;
}

static inline 
const_Slice_uint8_t
make_const_Slice_uint8 (const uint8_t *restrict p, size_t size)
{
    const_Slice_uint8_t s = { .p = p, .size = size };
    return s;
}

Ret_t mm(Slice_uint8_t target, const_Slice_uint8_t source)
{
    if(target.capacity >= source.size)
    {
        size_t i;
        for(i = 0; i < source.size; ++i)
        {
            target.p[i] = source.p[i];
        }
        return SUCCESS;
    }
    return FAILED;
}

int main()
{
    const char hello[] = "Hello World!";
    unsigned char buffer[100];
    unsigned char buffer1[100];

    printf("hello array length: %ld\nlength of hello string: %ld\n", ARRAY_CAPACITY(hello), strlen(hello));

    CHECK_ABORT_MAIN(mm(make_Slice_uint8(buffer,ARRAY_CAPACITY(buffer)),make_const_Slice_uint8((const uint8_t*)hello,strlen(hello) + 1)));
    printf( "buffer after mm(): %s\n", buffer);

    CHECK_ABORT_MAIN(mm(make_Slice_uint8(buffer1,ARRAY_CAPACITY(buffer1)),make_const_Slice_uint8(buffer,ARRAY_CAPACITY(buffer))));
    printf( "buffer1 after mm(): %s\n", buffer1);

    // Now, lets see if `restrict` wins us something:
    CHECK_ABORT_MAIN(mm(make_Slice_uint8(buffer1,ARRAY_CAPACITY(buffer1)),make_const_Slice_uint8(buffer1,ARRAY_CAPACITY(buffer1))));
    printf( "buffer1 after mm(): %s\n", buffer1);
    return 0;
}

pSlice_uint8_t中的成员const_Slice_uint8_t被标记为restrict ed。现在函数mm接受了这些结构的2个实例...这引起了我的问题:

在这种情况下,我可以期望编译器是聪明的并且使用那些restrict装饰吗?还是会使情况变得更糟(例如,通过引入未定义的行为)?

我用gcc -std=c99 -Wall -O3 -o main *.c编译了所有内容,并用0条警告,0条错误进行了编译。

1 个答案:

答案 0 :(得分:4)

  

我可以期望编译器更聪明并使用那些restrict吗?   在这种情况下装饰或使事情变得更糟(例如   通过引入未定义的行为)?

restrict限定符主要用于为编译器提供优化许可。唯一的语言 constraint (约束违例需要诊断)是只有对象指针可以是restrict限定的。从实现的质量考虑,您可以希望编译器能够诊断出违反限制条件的情况,但是实际上,没有编译器可以保证捕获所有违反情况。