Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 有效地将数据从一个整数类型转换为具有相同表示形式的另一个整数类型_C_Strict Aliasing - Fatal编程技术网

C 有效地将数据从一个整数类型转换为具有相同表示形式的另一个整数类型

C 有效地将数据从一个整数类型转换为具有相同表示形式的另一个整数类型,c,strict-aliasing,C,Strict Aliasing,大多数微机C编译器有两种大小和表示相同的有符号整数类型,以及两种无符号类型。如果int为16位,则其表示通常与short匹配;如果long是64位,它通常会匹配long;否则,int和long通常具有匹配的32位表示 如果在long、long和int64\t具有相同表示形式的平台上,需要按顺序将缓冲区传递给三个API函数(假设API在其他人的控制下,并使用指定的类型;如果可以随时更改函数,则可以简单地将其更改为始终使用相同的类型) 是否有任何有效的符合标准的方法来允许这三种情况 函数使用相同的缓

大多数微机C编译器有两种大小和表示相同的有符号整数类型,以及两种无符号类型。如果
int
为16位,则其表示通常与
short
匹配;如果
long
是64位,它通常会匹配
long
;否则,
int
long
通常具有匹配的32位表示

如果在
long
long
int64\t
具有相同表示形式的平台上,需要按顺序将缓冲区传递给三个API函数(假设API在其他人的控制下,并使用指定的类型;如果可以随时更改函数,则可以简单地将其更改为始终使用相同的类型)

是否有任何有效的符合标准的方法来允许这三种情况 函数使用相同的缓冲区,而不要求所有数据 在函数调用之间被复制?我怀疑C的别名规则的作者们认为这样的事情应该是困难的,但它在“现代”中很流行编译器假定通过
long*
写入的任何内容都不会通过
long*
读取,即使这些类型具有相同的表示形式。此外,虽然
int64\t
通常与
long
long
相同,但具体实现并不一致

在不通过函数调用积极追求基于类型的别名的编译器上,可以简单地将指针强制转换为正确的类型,可能包括一个静态断言,以确保所有类型都具有相同的大小。问题是,如果像gcc这样的编译器在扩展函数调用后,发现某些存储被编写为
long
和以后读取为
long
,在没有任何类型
long
的插入写入的情况下,即使存在类型
long
的插入写入,它也可以用类型为
long
的写入值替换后面读取的值

当然,完全禁用基于类型的别名是使 这样的代码是有效的。任何一个好的编译器都应该允许这样做,而且它会避免很多错误 其他可能的陷阱。不过,似乎应该有一个标准- 定义了有效执行此类任务的方法。有吗

有没有一种有效的符合标准的方法可以允许所有三个函数使用相同的缓冲区,而不需要在函数调用之间复制所有数据?我怀疑C的别名规则的作者打算这样做会很困难,但它在“现代”中很流行编译器假定通过long*写入的任何内容都不会通过long-long*读取,即使这些类型具有相同的表示形式

C指定
long
long
是不同的类型,即使它们具有相同的表示形式。无论表示形式如何,它们都不是标准定义的“兼容类型”。因此,严格的别名规则(C2011 6.5/7)应用:具有有效类型
long
的对象的存储值不应被类型为
long
的左值访问,反之亦然。因此,无论缓冲区的有效类型是什么,如果程序同时以类型
long
和类型
long访问元素,则程序将显示未定义的行为e> 

虽然我同意标准的作者并不想让你描述的东西变得困难,但他们也没有特别的意图让它变得容易。他们首先关心的是如何定义程序行为,尽可能地保持对实现所允许的所有自由的不变自由是指
long-long
可以具有与
long
不同的表示形式。因此,依赖于它们具有相同表示形式的程序,无论依赖的性质或上下文如何,都不能严格符合

不过,似乎应该有一个标准定义的方法来有效地执行这样的任务。有吗

否。缓冲区的有效类型是其声明的类型(如果有),或者是由其存储值的设置方式定义的。在后一种情况下,如果写入了不同的值,则可能会发生变化,但任何给定的值只有一个有效类型。无论其有效类型是什么,严格的别名规则都不允许t通过类型为
long
和类型为
long
的左值访问的值

当然,完全禁用基于类型的别名是使这些代码正常工作的一种方法。任何一个好的编译器都应该允许这样做,并且它将避免许多其他可能的陷阱

事实上,该方法或其他一些特定于实现的方法(可能包括It Just work)是在您提供的三个函数之间共享相同数据而无需复制的唯一替代方法

更新: 在某些受限情况下,可能会有一种更标准的解决方案。例如,使用指定的特定API函数,您可以执行以下操作:

union buffer {
    long       l[BUFFER_SIZE];
    long long ll[BUFFER_SIZE];
    int64_t  i64[BUFFER_SIZE]; 
} my_buffer;

fill_array(my_buffer.l, BUFFER_SIZE);
munge_array(my_buffer.i64, BUFFER_SIZE);
output_array(my_buffer.ll, BUFFER_SIZE);
(这是@Riley的道具,因为他给了我这个想法,尽管它和他的有点不同。)

当然,如果您的API动态地分配缓冲区本身,这是行不通的

  • 使用该方法的程序可能符合该标准,但如果它对
    long
    long
    int64_t
    采用相同的表示形式,则仍不严格符合该标准对该术语的定义

  • 这一标准在这一点上有点不一致。它关于允许通过
    联合
    进行类型双关的评论在脚注中,脚注是非规范性的。该脚注中描述的重新解释似乎相反
    union buffer {
        long       l[BUFFER_SIZE];
        long long ll[BUFFER_SIZE];
        int64_t  i64[BUFFER_SIZE]; 
    } my_buffer;
    
    fill_array(my_buffer.l, BUFFER_SIZE);
    munge_array(my_buffer.i64, BUFFER_SIZE);
    output_array(my_buffer.ll, BUFFER_SIZE);
    
    #include <limits.h>
    
    #if UINT_MAX == USHRT_MAX
    #  define INT_BUFFER ((unsigned*)short_buffer)
    #elif UINT_MAX == ULONG_MAX
    #  define INT_BUFFER ((unsigned*)long_buffer)
    #elif UINT_MAX == ULLONG_MAX
    #  define INT_BUFFER ((unsigned*)long_long_buffer)
    #else /* Fallback. */
      extern unsigned int_buffer[BUFFER_SIZE];
    #  define INT_BUFFER int_buffer
    #endif