繁体   English   中英

当 function 作为值参数传递给 function 时,如何更改原始变量?

[英]How can a function change the original variable, when it is passed as value argument to the function?

我有以下代码片段:

static const unsigned MAX_DIR_ITEMS = 4;

void fetchAlbum(int sd, const unsigned volref, const char *root, const char *name) {
    int dirItems = MAX_DIR_ITEMS;
    VFSDirInfo dirInfo[MAX_DIR_ITEMS];
    FileRef dirRef;

    if (dlp_VFSFileOpen(sd, volref, srcAlbumDir, vfsModeRead, &dirRef) < 0) {
        jp_logf(L_GUI, "Could not open dir '%s' on volume %d\n", srcAlbumDir, volref);
        return;
    }

    enum dlpVFSFileIteratorConstants itr = vfsIteratorStart;
    while (itr != vfsIteratorStop) {
        PI_ERR bytes;
        itr = vfsIteratorStart;
        jp_logf(L_DEBUG, "Enumerate dir '%s', dirRef=%d, itr=%d, dirItems=%d\n", srcAlbumDir, dirRef, (int)itr, dirItems);
        if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, (unsigned long *)&itr, &dirItems, dirInfo)) < 0) {
            jp_logf(L_FATAL, "Enumerate ERROR: bytes=%d, dirRef=%d, itr=%d, dirItems=%d\n", bytes, dirRef, (int)itr, dirItems);
            break;
        } else {
            jp_logf(L_DEBUG, "Enumerate OK: bytes=%d, dirRef=%d, itr=%d, dirItems=%d\n", bytes, dirRef, (int)itr, dirItems);
        }

使用的函数定义为:

/** @file pi-args.h
 *  @brief Macros for prototype definitions
 *
 */
#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) || defined(CAN_PROTOTYPE)
#   define PI_ARGS(x)       x
#   define PI_CONST const
#else
#   define PI_ARGS(x)       ()
#   define PI_CONST
#endif

typedef unsigned long FileRef;          /**< Type for file references when working with VFS files and directories. */

/** @name Expansion manager and VFS manager constants */
/*@{*/

    /** @brief VFS file iterator constants */
    enum dlpVFSFileIteratorConstants {
        vfsIteratorStart    = 0,        /** < Indicates that iterator is beginning */
        vfsIteratorStop     = -1        /**< Indicate that iterator has gone through all items */
    };

/*@}*/

/** @name Expansion manager functions */
/*@{*/

    /** @brief Iterate through the entries in a directory
     *
     * Supported on Palm OS 4.0 and later. At the beginning you set
     * @p dirIterator to #vfsIteratorStart, then call this function
     * repeatedly until it returns an error code of the iterator becomes
     * #vfsIteratorStop.
     *
     * @bug On some early OS 5 devices like Tungsten T and Sony NX70, NX73 this
     * call crashes the device. This has been confirmed to be a bug in HotSync on
     * the device, as tests showed that a regular HotSync conduit does crash the
     * device with this call too.
     *
     * @param sd Socket number
     * @param dirref Directory reference obtained from dlp_VFSFileOpen()
     * @param diriterator Ptr to an iterator. Start with #vfsIteratorStart
     * @param maxitems On input, the max number of VFSDirInfo structures stored in @p dirItems. On output, the actual number of items.
     * @param diritems Preallocated array that contains a number of VFSDirInfo structures on return.
     * @return A negative value if an error occured (see pi-error.h)
     */
    extern PI_ERR dlp_VFSDirEntryEnumerate
        PI_ARGS((int sd, FileRef dirref, unsigned long *diriterator,
            int *maxitems, struct VFSDirInfo *diritems));

/*@}*/

使用此代码,我得到以下令人惊讶的 output。 所以我想知道,变量dirRef如何改变它的值。

Enumerate dir '/Photos & Videos', dirRef=445317240, itr=0, dirItems=4
Enumerate OK: bytes=170, dirRef=0, itr=-1, dirItems=4

我使用的库来自这里: https://github.com/desrod/pilot-link

按值传递变量不提供在 function 内更改它的方法。

int foo(int x)
{
    x = x *2;
    return x;
}

变量x是自动局部变量,如果您在 function 中更改它,它不会影响按值传递给 function 的 object。

例子:

int main(void)
{
    int y = 4;
    foo(y);
    printf("%d\n", y);
}

Output: 4

您可以确定传递给此 function 的变量不会因为 function 内部参数的更改而改变。 它由 C 标准保证。

宏 PI_ARGS 是否有可能以不可见的方式改变某些东西?

不,您可以通过浏览您发布的 git 存储库自行轻松检查:

#if ((defined(__STDC__) || defined(SABER)) && !defined(NO_PROTOTYPE)) || defined(__cplusplus) || defined(USE_PROTOTYPE) || defined(CAN_PROTOTYPE)
#   define PI_ARGS(x)       x
#   define PI_CONST const
#else
#   define PI_ARGS(x)       ()
#   define PI_CONST
#endif

PS 有时人们会被宏之类的函数弄糊涂。

#define X2(x) ((x) = (x) * 2)

int main(void)
{
    int y = 5;
    X2(y);

    printf("%d\n", y);
}

我已经通过以下代码找到了问题的原因。

看来, unsigned long在我的机器上有 64 位。 我一直认为,对于 64 位变量,我需要unsigned long long 因此,当 function dlp_VFSDirEntryEnumerate()返回时, itr将作为故障写回 64 位值,并且变量dirItems被部分覆盖。 唯一的谜团是, dirItems变为0而不是ffffffff

static const unsigned MIN_DIR_ITEMS = 16;
static const unsigned MAX_DIR_ITEMS = 1024;

    void fetchAlbum(int sd, const unsigned volref, const char *root, const char *name) {
        int dirItems = MIN_DIR_ITEMS;
        VFSDirInfo dirInfos[MAX_DIR_ITEMS];
        char srcAlbumDir[strlen(root) + (name ? strlen(name) : 0) + 2];
        FileRef dirRef;
    
        printf("[GUI]     Fetching album '%s' on volume %d\n", name, volref);
    
        strcpy(srcAlbumDir, root); // Album is in /<root>/<name>.
        // Unfiled album is really just root dir.
        if (name) {
            strcat(strcat(srcAlbumDir, "/"), name);
        }
        if (dlp_VFSFileOpen(sd, volref, srcAlbumDir, vfsModeRead, &dirRef) < 0) {
            return;
        }
    
        // Iterate over all the files in the album dir, looking for jpegs and 3gp's and 3g2's (videos).
        enum dlpVFSFileIteratorConstants itr = vfsIteratorStart;
        printf("[DEBUG]   &dirItems='%p', sizeof(dirItems)=%lu\n", &dirItems, sizeof(dirItems));
        printf("[DEBUG]   &dirRef=  '%p', sizeof(dirRef)=%lu\n", &dirRef, sizeof(dirRef));
        printf("[DEBUG]   &itr=     '%p', sizeof(itr)=%lu\n", &itr, sizeof(itr));
        printf("[DEBUG]   sizeof(int)=%lu\n", sizeof(int));
        printf("[DEBUG]   sizeof(long)=%lu\n", sizeof(long));
        printf("[DEBUG]   sizeof(unsigned)=%lu\n", sizeof(unsigned));
        printf("[DEBUG]   sizeof(unsigned long)=%lu\n", sizeof(unsigned long));
        printf("[DEBUG]   sizeof(unsigned long long)=%lu\n", sizeof(unsigned long long));

        for (int dirItems_backup; (dirItems_backup = dirItems) <= MAX_DIR_ITEMS; dirItems *= 2) {
            PI_ERR bytes;
            itr = vfsIteratorStart;
            FileRef dirRef_backup = dirRef; // Unfortunately the following call deletes the original value
            printf("[DEBUG]    Enumerate album '%s', dirRef=%llx, itr=%llx, dirItems=%d\n", srcAlbumDir, dirRef, (long long int)itr, dirItems);
            if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, (unsigned long *)&itr, &dirItems, dirInfos)) < 0) {
                printf("[FATAL]    Enumerate ERROR: bytes=%d, dirRef=%llx, itr=%llx, dirItems=%d\n", bytes, dirRef, (long long int)itr, dirItems);
                break;
            }
            printf("[DEBUG]    Enumerate OK: bytes=%d, dirRef=%llx, itr=%llx, dirItems=%d\n", bytes, dirRef, (long long int)itr, dirItems);
            dirRef = dirRef_backup;
            printf("[DEBUG]    Rescued from backup: dirRef=%llx\n", dirRef);
            if (dirItems < dirItems_backup) {
                break;
            }
        }
        dlp_VFSFileClose(sd, dirRef);
        [.....] // process files from the retrieved dirInfos
        return;
    }

这是我得到的 output:

[GUI]     Fetching album '(null)' on volume 1
[DEBUG]   &dirItems='0x7ffee6335848', sizeof(dirItems)=4
[DEBUG]   &dirRef=  '0x7ffee6335850', sizeof(dirRef)=8
[DEBUG]   &itr=     '0x7ffee633584c', sizeof(itr)=4
[DEBUG]   sizeof(int)=4
[DEBUG]   sizeof(long)=8
[DEBUG]   sizeof(unsigned)=4
[DEBUG]   sizeof(unsigned long)=8
[DEBUG]   sizeof(unsigned long long)=8
[DEBUG]    Enumerate album '/Photos & Videos', dirRef=20a70070, itr=0, dirItems=16
[DEBUG]    Enumerate OK: bytes=170, dirRef=0, itr=ffffffffffffffff, dirItems=8
[DEBUG]    Rescued from backup: dirRef=20a70070

所以现在正确的代码是:

        unsigned long itr;
        [.....]
            itr = (unsigned long)vfsIteratorStart;
            if ((bytes = dlp_VFSDirEntryEnumerate(sd, dirRef, &itr, &dirItems, dirInfos)) < 0) {

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM