سؤال

أنا أحاول التكيف القائمة رمز 64 بت الجهاز.المشكلة الرئيسية هي أن في وظيفة واحدة ، السابقة المبرمج يستخدم الفراغ* حجة أن يتم تحويلها إلى نوع مناسب في الوظيفة نفسها.قصيرة على سبيل المثال:

void function(MESSAGE_ID id, void* param)
{
    if(id == FOO) {
        int real_param = (int)param;
        // ...
    }
}

بالطبع على 64 بت الجهاز أحصل على خطأ:

error: cast from 'void*' to 'int' loses precision

أود أن تصحيح هذا بحيث أنه لا يزال يعمل على 32 بت آلة نظيفة قدر الإمكان.أي فكرة ؟

هل كانت مفيدة؟

المحلول

استخدام intptr_t و uintptr_t.

للتأكد من أنه يتم تعريف في المحمولة الطريقة ، يمكنك استخدام رمز مثل هذا:

#if defined(__BORLANDC__)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
    typedef unsigned long uintptr_t;
#elif defined(_MSC_VER)
    typedef unsigned char uint8_t;
    typedef __int64 int64_t;
#else
    #include <stdint.h>
#endif

فقط ضع هذا في بعض .ساعة الملف وتشمل أينما كنت في حاجة إليها.

بدلا من ذلك, يمكنك تحميل نسخة مايكروسوفت من stdint.h الملف من هنا أو استخدام محمول واحد من هنا.

نصائح أخرى

أود أن أقول هذا هو الحديث C++ الطريقة.

#include <cstdint>
void *p;
auto i = reinterpret_cast<std::uintptr_t>(p);

تحرير:

النوع الصحيح إلى عدد صحيح

لذا الطريقة الصحيحة لتخزين مؤشر صحيحا هو استخدام uintptr_t أو intptr_t أنواع.(انظر أيضا في cppreference صحيح أنواع C99).

هذه الأنواع هي محددة في <stdint.h> بالنسبة C99 و في مساحة الاسم std C++11 في <cstdint> (انظر صحيح أنواع C++).

C++11 (فصاعدا) نسخة

#include <cstdint>
std::uintptr_t i;

C++03 الإصدار

extern "C" {
#include <stdint.h>
}

uintptr_t i;

C99 الإصدار

#include <stdint.h>
uintptr_t i;

الصحيح صب المشغل

في ج هناك واحد فقط الزهر باستخدام C يلقي في C++ مكروها (حتى لا تستخدم في C++).في C++ هناك مختلفة يلقي. reinterpret_cast هو الصحيح يلقي هذا التحويل (انظر أيضا هنا).

C++11 نسخة

auto i = reinterpret_cast<std::uintptr_t>(p);

C++03 الإصدار

uintptr_t i = reinterpret_cast<uintptr_t>(p);

ج الإصدار

uintptr_t i = (uintptr_t)p; // C Version

أسئلة ذات صلة

'size_t" و "ptrdiff_t' هناك حاجة إلى تطابق العمارة (أيا كان).ولذلك أعتقد بدلا من استخدام 'int' ، يجب أن تكون قادرا على استخدام 'size_t' ، والتي على نظام 64 بت يجب أن يكون 64 بت نوع.

هذا النقاش unsigned int مقابل size_t يذهب إلى أكثر قليلا من التفصيل.

استخدام uintptr_t كما نوع عدد صحيح.

عدة إجابات قد أشار في uintptr_t و #include <stdint.h> ك '' الحل.أن أرى جزءا من الجواب ، ولكن ليس كل إجابة.أنت أيضا بحاجة إلى أن ننظر إلى حيث يتم استدعاء الدالة مع رسالة معرف فو.

النظر في هذا القانون و تجميع:

$ cat kk.c
#include <stdio.h>
static void function(int n, void *p)
{
    unsigned long z = *(unsigned long *)p;
    printf("%d - %lu\n", n, z);
}

int main(void)
{
    function(1, 2);
    return(0);
}
$ rmk kk
        gcc -m64 -g -O -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith \
            -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes \
            -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE kk.c -o kk 
kk.c: In function 'main':
kk.c:10: warning: passing argument 2 of 'func' makes pointer from integer without a cast
$

سوف نلاحظ أن هناك مشكلة في الموقع داعيا (في main()) — تحويل عدد صحيح في المؤشر دون المدلى بها.أنت ذاهب إلى الحاجة إلى تحليل function() في جميع الأعراف لنرى كيف يتم تمرير القيم إلى ذلك.التعليمات البرمجية داخل بلدي function() أن العمل إذا كان يدعو كتبت:

unsigned long i = 0x2341;
function(1, &i);

منذ لك ربما تكون مكتوبة بشكل مختلف تحتاج إلى مراجعة نقاط حيث يتم استدعاء الدالة على ضمان أنه من المنطقي أن استخدام القيمة كما هو مبين.لا تنسى قد يكون إيجاد علة كامنة.

أيضا, إذا كنت تسير على شكل قيمة void * المعلمة (المحولة) ، ننظر بعناية في <inttypes.h> رأس (بدلا من stdint.hinttypes.h يوفر خدمات stdint.h, وهو أمر غير معتاد ولكن C99 القياسية يقول [t]أنه رأس <inttypes.h> يتضمن رأس <stdint.h> و يمتد ذلك مع تشتمل المرافق الإضافية المقدمة من قبل استضافت تطبيقات) واستخدام PRIxxx وحدات الماكرو في شكل سلاسل.

أيضا ، تعليقاتي بدقة تنطبق C وليس C++, ولكن التعليمات البرمجية الخاصة بك في مجموعة فرعية من C++ المحمولة بين C و C++.فرص عادلة جيدة أن تعليقاتي تطبيق.

  1. #include <stdint.h>
  2. استخدام uintptr_t نوع قياسي محدد في تضمين معيار رأس الملف.

أعتقد أن "معنى" من الفراغ* في هذه الحالة هو عام في التعامل معها.ليس من مؤشر إلى القيمة هو قيمة في حد ذاته.(هذا يحدث لمجرد أن يكون مدى الفراغ* يستخدم من قبل C و C++ المبرمجين.)

إذا كان عقد قيمة عدد صحيح ، قد يكون من الأفضل في صحيح المدى!

هنا هي سهلة يرجع إلى عدد صحيح:

int x = (char*)p - (char*)0;

إلا أنه ينبغي إعطاء تحذير.

جئت عبر هذا السؤال أثناء الدراسة البرمجية المصدر سكليتي.

في sqliteInt.ح, هناك فقرة من رمز تعريف ماكرو تحويل بين صحيح و المؤشر.المؤلف قدم جيدة للغاية البيان الأول مشيرا إلى أنه ينبغي أن يكون مترجم تعتمد المشكلة ومن ثم تنفيذ الحل لحساب الأكثر شعبية المجمعين هناك.

#if defined(__PTRDIFF_TYPE__)  /* This case should work for GCC */
# define SQLITE_INT_TO_PTR(X)  ((void*)(__PTRDIFF_TYPE__)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(__PTRDIFF_TYPE__)(X))
#elif !defined(__GNUC__)       /* Works for compilers other than LLVM */
# define SQLITE_INT_TO_PTR(X)  ((void*)&((char*)0)[X])
# define SQLITE_PTR_TO_INT(X)  ((int)(((char*)X)-(char*)0))
#elif defined(HAVE_STDINT_H)   /* Use this case if we have ANSI headers */
# define SQLITE_INT_TO_PTR(X)  ((void*)(intptr_t)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(intptr_t)(X))
#else                          /* Generates a warning - but it always works     */
# define SQLITE_INT_TO_PTR(X)  ((void*)(X))
# define SQLITE_PTR_TO_INT(X)  ((int)(X))
#endif

و هنا اقتباس من تعليق لمزيد من التفاصيل:

/*
** The following macros are used to cast pointers to integers and
** integers to pointers.  The way you do this varies from one compiler
** to the next, so we have developed the following set of #if statements
** to generate appropriate macros for a wide range of compilers.
**
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that vary from one machine to the next.
**
** Ticket #3860:  The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct.  But MSVC chokes on ((void*)(X)).
** So we have to define the macros in different ways depending on the
** compiler.
*/

الائتمان يذهب إلى committers.

أفضل شيء القيام به هو تجنب تحويل من نوع مؤشر غير مؤشر أنواع.ولكن هذا هو واضح ليس من الممكن في هذه الحالة.

كما قال الجميع ، uintptr_t هو ما يجب أن تستخدم.

هذا الرابط لديه معلومات جيدة عن تحويل رمز 64 بت.

هناك أيضا مناقشة جيدة من هذا على comp.الأمراض المنقولة جنسيا.ج

منذ uintptr_t هو لا يضمن أن تكون هناك في++C/C++11, إذا كان هذا هو واحد طريقة التحويل يمكنك أن تنظر في uintmax_t, دائما المحددة في <cstdint>.

auto real_param = reinterpret_cast<uintmax_t>(param);

للعب آمنة أن تضاف في أي مكان في كود التأكيد:

static_assert(sizeof (uintmax_t) >= sizeof (void *) ,
              "No suitable integer type for conversion from pointer type");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top