C中的以下代码是否定义了行为?
int main() {
const int i = 0;
return *(int*)(&i);
}
Run Code Online (Sandbox Code Playgroud)
我问,因为6.5/7列出了"与对象的有效类型兼容的类型的合格版本"作为有效别名.但是对象的有效类型是const int,我认为不是int合格版本const int(尽管反之亦然).既不是int和const int兼容(6.7.3/10).
此外,6.3.2.3/2表示您可以通过添加限定符来转换指针类型,并且结果指针是相等的.6.3.2.3/7表示你可以转换任何两种指针类型(因此(int*)(&i)允许转换本身).但是并没有说结果指针指的是同一个对象,甚至它是相等的.它说的是它可以转换回原始类型(在这种情况下const int*).也就是说,即使别名是合法的,我也不清楚标准是否保证我的指针转换确实会导致指向的指针i.
那么,标准是否实际定义了我的代码的行为,如果是,那么这个定义在哪里?
我知道代码在实践中有效.我想到了一个不起作用的假设(和奇怪)实现.我可以问这个实现是否符合标准(如果不符合,它违反了哪个部分),但如果还有其他方面,我想象的实现无法符合,我不想浑水.如果有人认为这将有助于他们回答问题,我将描述实施.
例如,此代码是有效的,还是通过违反别名规则来调用未定义的行为?
int x;
struct s { int i; } y;
x = 1;
y = *(struct s *)&x;
printf("%d\n", y.i);
Run Code Online (Sandbox Code Playgroud)
我的兴趣在于使用基于此的技术来开发用于执行别名读取的可移植方法.
更新:这是预期的用例,有点不同,但当且仅当上述内容有效时才有效:
static inline uint32_t read32(const unsigned char *p)
{
struct a { char r[4]; };
union b { struct a r; uint32_t x; } tmp;
tmp.r = *(struct a *)p;
return tmp.x;
}
Run Code Online (Sandbox Code Playgroud)
GCC根据需要将其编译为单个32位负载,并且它似乎避免了如果p实际指向除其他类型之外可能发生的混叠问题char.换句话说,它似乎是GNU C __attribute__((__may_alias__))属性的可移植替代品.但我不确定它是否真的定义明确......
考虑以下valarray类:
#include <stdlib.h>
struct va
{
void add1(const va& other);
void add2(const va& other);
size_t* data;
size_t size;
};
void va::add1(const va& other) {
for (size_t i = 0; i < size; ++i) {
data[i] += other.data[i];
}
}
void va::add2(const va& other){
for (size_t i = 0, s = size; i < s; ++i) {
data[i] += other.data[i];
}
}
Run Code Online (Sandbox Code Playgroud)
该add2函数针对不同的编译器(MSVC、Clang、GCC、ICC)进行了向量化,而add1并非如此。参见https://godbolt.org/z/c61qvrrbv
这是通过潜在的别名来解释的:编译器无法证明所指向的元素之一data不是其size本身。
data然而,和指向的元素也可能存在重叠other.data。对于 MSVC,这些元素和指针本身可能存在别名,因为它没有利用严格别名规则。这适用于add1 …
c++ vectorization strict-aliasing compiler-optimization auto-vectorization
在这些评论用户@Deduplicator坚持认为,严格别名规则允许通过一个不兼容的类型的访问,如果任一混叠或混叠指针的是一个指针到字符的类型(合格或不合格,符号或无符号char *).所以,他的断言基本上都是这两个
long long foo;
char *p = (char *)&foo;
*p; // just in order to dereference 'p'
Run Code Online (Sandbox Code Playgroud)
和
char foo[sizeof(long long)];
long long *p = (long long *)&foo[0];
*p; // just in order to dereference 'p'
Run Code Online (Sandbox Code Playgroud)
符合并定义了行为.
但是,在我的阅读中,它只是第一种有效的形式,也就是说,当别名指针是指向char的指针时; 但是,在另一个方向上不能这样做,即当别名指针指向不兼容的类型(字符类型除外)时,别名指针为a char *.
所以,上面的第二个片段会有未定义的行为.
情况怎样?它是否正确?为了记录,我已经阅读了这个问题和答案,并且接受的答案明确指出了这一点
规则允许例外
char *.它总是假设char *其他类型别名.但是这不会起作用,没有假设你的结构别名为chars的缓冲区.
(强调我的)
我读的越多,我就越困惑.
相关问题的最后一个问题与我的问题最接近,但是我对所有关于对象生命周期的问题感到困惑,尤其是 - 只读或不读.
直截了当.如我错了请纠正我.
这很好,gcc没有发出警告,我正试图" 通过" 读取类型T(uint32_t)char*:
uint32_t num = 0x01020304;
char* buff = reinterpret_cast< char* >( &num );
Run Code Online (Sandbox Code Playgroud)
但这是"坏"(也是一个警告),我正在尝试"反过来":
char buff[ 4 ] = { 0x1, 0x2, 0x3, 0x4 };
uint32_t num = *reinterpret_cast< uint32_t* >( buff );
Run Code Online (Sandbox Code Playgroud)
第二个如何与第一个不同,特别是当我们谈论重新排序指令(用于优化)时?另外,添加const不会以任何方式改变这种情况.
或者这只是一条直接规则,它明确指出:"这可以在一个方向完成,但在另一个方向不能完成"?我在标准中找不到任何相关内容(特别是在C++ 11标准中搜索过).
C和C++是否相同(因为我读了一条评论,暗示它与2种语言不同)?
我曾经union"解决"这个问题,但仍然看起来并非 100%正常,因为标准无法保证(这表明我只能依赖于最后一次修改的值union).
所以,经过大量阅读,我现在更加困惑.我想只是memcpy"好"的解决方案?
相关问题:
编辑
现实世界的情况:我有一个第三方库(http://www.fastcrypto.org/),它计算UMAC并返回值char[ 4 ].然后我需要将其转换为uint32_t.而且,顺便说一句,lib使用的东西((UINT32 …
考虑这两个功能:
int f1()
{
alignas(int) char buf[sizeof(int)] = {};
return *reinterpret_cast<int*>(buf);
}
int f2()
{
alignas(int) char buf[sizeof(int)] = {};
char* ptr = buf;
return *reinterpret_cast<int*>(ptr);
}
Run Code Online (Sandbox Code Playgroud)
GCC警告说,第一个违反严格别名规则.但第二个是好的.
Clang接受了两个没有投诉.
警告是否合法?
c++ strict-aliasing compiler-warnings language-lawyer reinterpret-cast
我无法解释这个程序的执行行为:
#include <string>
#include <cstdlib>
#include <stdio.h>
typedef char u8;
typedef unsigned short u16;
size_t f(u8 *keyc, size_t len)
{
u16 *key2 = (u16 *) (keyc + 1);
size_t hash = len;
len = len / 2;
for (size_t i = 0; i < len; ++i)
hash += key2[i];
return hash;
}
int main()
{
srand(time(NULL));
size_t len;
scanf("%lu", &len);
u8 x[len];
for (size_t i = 0; i < len; i++)
x[i] = rand();
printf("out %lu\n", f(x, len));
}
Run Code Online (Sandbox Code Playgroud)
因此,当使用带有gcc的-O3编译并使用参数25运行时,它会引发段错误.没有优化它工作正常.我已经对它进行了反汇编:它正在进行矢量化,并且编译器假定 …
哪些代码有UB(具体来说,哪些违反了严格的别名规则)?
void a() {
std::vector<char> v(sizeof(float));
float *f = reinterpret_cast<float *>(v.data());
*f = 42;
}
void b() {
char *a = new char[sizeof(float)];
float *f = reinterpret_cast<float *>(a);
*f = 42;
}
void c() {
char *a = new char[sizeof(float)];
float *f = new(a) float;
*f = 42;
}
void d() {
char *a = (char*)malloc(sizeof(float));
float *f = reinterpret_cast<float *>(a);
*f = 42;
}
void e() {
char *a = (char*)operator new(sizeof(float));
float *f = reinterpret_cast<float *>(a);
*f = …Run Code Online (Sandbox Code Playgroud) 放置new的返回值与其操作数的转换值之间是否存在(语义)差异?
struct Foo { ... };
char buffer[...];
Foo *a = new(buffer) Foo;
Foo *b = reinterpret_cast<Foo *>(buffer);
Run Code Online (Sandbox Code Playgroud)
是否a和b以某种方式有什么不同?
编辑:根据DaBler的评论,这个问题告诉我,如果使用const/reference成员则存在差异:使用const成员放置新类和赋值
所以,我的小位的更新问题:是否a和b以任何方式不同,如果Foo没有const或引用成员?
c++ strict-aliasing placement-new language-lawyer reinterpret-cast
在C ++中,存在一个别名漏洞,该漏洞允许通过某些字符类型的指针来读取或写入任何对象的对象表示。
这仅适用于char和unsigned char还是适用于signed char?