- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
所以我有以下最小化的 C11 代码,它定义了一个包含 uint16_t 的结构(这意味着它应该对齐到 2 个字节的结构),我想将一个 char 缓冲区转换为指向该结构的指针。
随着警告全部出现,clang 正确地提示不满足结构的对齐要求。所以我向缓冲区添加了一个 C11 alignas
说明符以确保缓冲区充分对齐,但这并没有关闭 clang。
我的问题是:我对 alignas
做错了吗?或者只是 -Wcast-align 诊断只查看参数的类型而不是手动指定的对齐方式? (我知道我可以转换为 void*
来停止诊断,但是由于这段代码应该是可移植的,所以我不想回避诊断,除非我确定它是误报。)
#include <stdint.h>
#include <stdalign.h>
struct foo {
uint16_t field1;
};
int main(void) {
alignas(struct foo) char buffer[122] = {0};
struct foo *foo = (struct foo*)buffer;
return foo->field1;
}
编译器选项和错误信息:
$ clang -ggdb -O3 foo.c -Weverything -Werror -Wno-c++98-compat -Wno-c11-extensions
foo.c:11:23: error: cast from 'char *' to 'struct foo *' increases required alignment from 1 to 2 [-Werror,-Wcast-align]
struct foo *foo = (struct foo*)buffer;
^~~~~~~~~~~~~~~~~~~~~~~~~
编译器版本:
$ clang -v
clang version 3.5.1 (tags/RELEASE_351/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4
更新:当我将缓冲区及其对齐方式移动到结构中时,没有任何警告。我将此解释为 clang 确实只查看此警告的类型的提示。
#include <stdint.h>
#include <stdalign.h>
struct foo {
uint16_t field1;
};
struct bar {
alignas(struct foo) char buffer[122];
};
int main(void) {
struct bar bar = {{0}};
struct foo *foo = (struct foo*)&bar;
return foo->field1;
}
最佳答案
从 clang 来源,在 SemaChecking.cpp:~7862 中,他们似乎只关注你提到的类型:
CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee);
if (SrcAlign >= DestAlign) return;
// else warn...
在我看来,clang 正在准备一个 c 风格的转换,而后者又会检查转换对齐。
void CastOperation::CheckCStyleCast()
-> Kind = CastKind Sema::PrepareScalarCast(...);
-> if (Kind == CK_BitCast)
checkCastAlign();
void checkCastAlign() {
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}
这里是带有更多上下文的方法:
/// CheckCastAlign - Implements -Wcast-align, which warns when a
/// pointer cast increases the alignment requirements.
void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// This is actually a lot of work to potentially be doing on every
// cast; don't do it if we're ignoring -Wcast_align (as is the default).
if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin()))
return;
// Ignore dependent types.
if (T->isDependentType() || Op->getType()->isDependentType())
return;
// Require that the destination be a pointer type.
const PointerType *DestPtr = T->getAs<PointerType>();
if (!DestPtr) return;
// If the destination has alignment 1, we're done.
QualType DestPointee = DestPtr->getPointeeType();
if (DestPointee->isIncompleteType()) return;
CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee);
if (DestAlign.isOne()) return;
// Require that the source be a pointer type.
const PointerType *SrcPtr = Op->getType()->getAs<PointerType>();
if (!SrcPtr) return;
QualType SrcPointee = SrcPtr->getPointeeType();
// Whitelist casts from cv void*. We already implicitly
// whitelisted casts to cv void*, since they have alignment 1.
// Also whitelist casts involving incomplete types, which implicitly
// includes 'void'.
if (SrcPointee->isIncompleteType()) return;
CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee);
if (SrcAlign >= DestAlign) return;
Diag(TRange.getBegin(), diag::warn_cast_align)
<< Op->getType() << T
<< static_cast<unsigned>(SrcAlign.getQuantity())
<< static_cast<unsigned>(DestAlign.getQuantity())
<< TRange << Op->getSourceRange();
}
static const Type* getElementType(const Expr *BaseExpr) {
const Type* EltType = BaseExpr->getType().getTypePtr();
if (EltType->isAnyPointerType())
return EltType->getPointeeType().getTypePtr();
else if (EltType->isArrayType())
return EltType->getBaseElementTypeUnsafe();
return EltType;
}
关于C11 alignas 与 clang -Wcast-align,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28516413/
我有一个类型为 const char * 的变量 k,以及一个带有原型(prototype)的 glib 函数 void g_hash_table_replace(GHashTable *hash_t
我收到以下警告: cast between incompatible function types from ‘int (*)(pile *)’ {aka ‘int (*)(struct pile *
我正在阅读 an introduction to gcc其中说: ‘-Wcast-qual’ this option warns about pointers that are cast to rem
所以我有以下最小化的 C11 代码,它定义了一个包含 uint16_t 的结构(这意味着它应该对齐到 2 个字节的结构),我想将一个 char 缓冲区转换为指向该结构的指针。 随着警告全部出现,cla
如果我们有void foo(const char * const ** bar);我们用 char *** bar = malloc(...); 来调用它如foo((const char * cons
对于代码: static const char *a = NULL; abc((char **)&a); abc 方法定义为: abc(char** a) 我收到错误(警告被视为错误): erro
我知道 gcc 有一个选项 -Wcast-align,它会在每次转换指针时发出警告,从而增加目标的对齐要求。 这是我的程序: char data[10]; int ptr = *((int *)dat
编辑:问题解释得更深入 here (谢谢@Eric Postpischil)。这似乎是 GCC 中的一个错误。 首先,让我从一些上下文开始:我正在编写的代码使用了一个我无法更改的 API,在我无法更改
这是我的测试程序: #include #pragma GCC diagnostic ignored "-Wcast-qual" static void proc(char *buf) { p
static char buf[8]; void foo(){ const char* ptr = buf; /* ... */ char* q = (char*)ptr; }
有没有办法让我使用 c++11 关键字 alignas装饰函数get() .在某些情况下,我知道 get() 返回的缓冲区将包含正确对齐的浮点缓冲区。 代码: $ cat c.cxx extern c
我是一名优秀的程序员,十分优秀!