编辑:问题更深入地解释了here(谢谢@Eric Postpischil)。这似乎是GCC中的错误。
首先,让我从一些上下文开始:我正在编写的代码使用的是我无法更改的API,在我无法更改的GCC版本上,带有不允许删除的编译标志,以及当我完成后,它必须正好是零警告或#pragmas。
编辑:也没有工会。
EDIT2:假定构建系统还使用-Wall -ansi -pedantic以及在阳光下的所有其他警告。 我明天将确认GCC版本,但我可以肯定它不在GCC 7之上。与此同时,我正在使用GCC 6.3进行测试。
EDIT3:我将此问题标记为“已回答”。为了完整起见,我在下面添加了更多信息:
我已经检查了正在使用的编译器版本,它并不漂亮。我们使用的是Mingw,gcc.exe --version
告诉我它是GCC 3.4.5。
此外,编译标志包括wall wextra wcast-qual wpointer-arith wconversion wsign-conversion
以及与当前问题不相关的其他标志。
考虑以下代码:
#include "stdio.h"
#include "stdint.h"
typedef uint32_t MyType[4];
const MyType* foo(const uint8_t* a)
{
return (const MyType*) a;
}
void myapi_foo(const MyType* d) {}
int main()
{
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
myapi_foo(b);
return 0;
}
使用GCC和-Wcast-qual标志进行编译,此代码将引发以下警告:
警告:强制转换会从指针目标类型[-Wcast-qual]中丢弃“ const”限定词 return(const MyType *)a;
编辑:澄清一下,错误在这一行:
return (const MyType*) a;
我知道问题的根本原因是typedef类型MyType
,它实际上是一个数组。可悲的是,我没有修改这个typedef的奢侈,也没有API函数myapi_foo
及其参数类型的可疑选择。
老实说,我不真正理解为什么为何编译器对此强制转换不满意,因此澄清起来实在值得欢迎。
最干净向编译器指示所有内容都应视为指向const数据的指针的方式是什么?
以下是我找到的一些“解决方案”,但令我不满意:
return (const MyType*) (uint32_t) a;
。 非常很粗糙,但是使用uint32_t
作为内存地址在该项目中是先例,因此我可能不得不将其用作最后的尝试。return (const void*) a;
,无论sizeof(MyType*)
的值如何,它都可以工作。遗憾的是,它对目标不起作用。谢谢您的时间。
答案 0 :(得分:2)
这是GCC bug 81631。 GCC无法识别对const MyType *
的强制类型转换保留了const
限定符。这可能是因为,在此“指向四个const uint32_t
的数组的指针”中,GCC对数组是否为const
以及数组元素是否为const
进行了测试。>
在某些GCC版本(包括8.2)中,一种解决方法是更改:
return (const MyType*) a;
收件人:
return (const void *) a;
可能会在更多版本中使用的更剧烈的更改是使用:
return (const MyType *) (uintptr_t) a;
此代码将a
传递给将其强制转换为const MyType *
的函数可能是一个问题:
uint8_t a[4*sizeof(uint32_t)];
const MyType* b = foo((const uint8_t*) a);
在许多C实现中,MyType
是uint32_t
的数组,将需要四字节对齐,但是a
仅需要一字节对齐。根据C 2018 6.3.2.3 6,如果a
未正确对齐MyType
,则转换结果未定义。
此外,此代码建议将uint_t
数组a
用作四个uint32_t
的数组。这将违反C别名规则。您在问题中显示的代码似乎只是示例,而不是实际的代码,因此我们不能确定,但是您应该考虑一下。
答案 1 :(得分:1)
您可以这样做:
const MyType* foo(const uint8_t* a)
{
union {
const uint8_t* a;
const MyType* b;
} v;
v.a = a;
return v.b;
}
w.c 是您的修改文件:
pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi@raspberrypi:/tmp $
无论编译器(没有 #pragma )还是int和pointer的各自大小(在int和pointer之间都没有强制转换),该方法都可以工作,但是我不确定这是否非常优雅; / p>
具有 foo 函数并同时与Wcast-qual
一起编译是很奇怪的,这是矛盾的
编辑,如果您不能使用 union ,您也可以这样做
const MyType* foo(const uint8_t* a)
{
const MyType* r;
memcpy(&r, &a, sizeof(a));
return r;
}
编译:
pi@raspberrypi:/tmp $ gcc -pedantic -Wall -Wcast-qual w.c
pi@raspberrypi:/tmp $
答案 2 :(得分:1)
如果没有任何效果,则您可以使用uintptr_t
hammer(如果实现可以提供)。根据C11标准,它是可选的:
public class MessageService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if(remoteMessage.getData().isEmpty())
showNotification(remoteMessage.getNotification().getTitle(),remoteMessage.getNotification().getBody(),remoteMessage.getData().get("url"));
else
showNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"),remoteMessage.getData().get("url"));
}
private void showNotification(String title, String body, String url) {
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("url",url);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addNextIntentWithParentStack(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
//Uri sound =Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/" + R.raw.notification);
//Uri sound = Uri.parse("android.resource://" + getApplicationContext().getPackageName() + "/raw/notification");
Uri sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + File.pathSeparator + File.separator + getPackageName() + "/raw/notification.mp3");
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String NOTIFICATION_CHANNEL_ID = "com.example.alibapir.test";
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher_ali_bapir_round)
.setSound(sound)
.setContentTitle(title)
.setContentText(body)
.setContentInfo("info")
.setContentIntent(resultPendingIntent);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel notificationChannel= new NotificationChannel(NOTIFICATION_CHANNEL_ID,"Notification",NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setDescription("Ali Bapir notification");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setVibrationPattern(new long[]{0,1000,500,1000});
notificationChannel.enableLights(true);
notificationChannel.setSound(sound , new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_ALARM).build());
notificationManager.createNotificationChannel(notificationChannel);
}
notificationManager.notify(new Random().nextInt(), notificationBuilder.build());
}
}